2 Commits

Author SHA1 Message Date
rboullard b2220d981f References. Removed testing, will rewrite the tests tomorrow
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Successful in 6m14s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Successful in 5m44s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Successful in 6m8s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Successful in 6m4s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Successful in 6m23s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Successful in 6m26s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Successful in 9m35s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Successful in 7m21s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Successful in 6m14s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Successful in 6m12s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Successful in 7m11s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Successful in 6m59s
Bigfoot / Clang Format Checks (push) Successful in 1m42s
2026-07-31 18:27:05 +02:00
rboullard 33944d0b7d Extract slotkey from slotmap 2026-07-30 23:17:28 +02:00
32 changed files with 1570 additions and 1392 deletions
+10 -6
View File
@@ -37,22 +37,23 @@ static_assert(sizeof(MyComplexStruct) == 64, "Payload should be exactly one cach
static_assert(std::is_trivially_copyable_v<MyComplexStruct>,
"Container moves should be a plain memcpy, not a heap-touching move.");
template<class SLOTMAP>
class SlotMapAdaptor
{
public:
using Key = SlotMap<MyComplexStruct>::SlotKey;
using Key = SlotMapKey;
Key Add(MyComplexStruct&& p_value)
SlotMapKey Add(MyComplexStruct&& p_value)
{
return m_container.Insert(std::move(p_value));
}
const MyComplexStruct* Find(const Key p_key) const
const MyComplexStruct* Find(const SlotMapKey p_key) const
{
return m_container.Get(p_key);
}
void Remove(const Key p_key)
void Remove(const SlotMapKey p_key)
{
m_container.Remove(p_key);
}
@@ -72,7 +73,7 @@ class SlotMapAdaptor
}
private:
SlotMap<MyComplexStruct> m_container;
SLOTMAP m_container;
};
template<class MAP>
@@ -233,13 +234,16 @@ void Iterate(benchmark::State& state)
BENCHMARK_TEMPLATE(Get, ADAPTOR)->Name(NAME "/Get")->Arg(512)->Arg(8192)->Arg(262'144)->Arg(4'194'304); \
BENCHMARK_TEMPLATE(Iterate, ADAPTOR)->Name(NAME "/Iterate")->Arg(512)->Arg(8192)->Arg(262'144)->Arg(4'194'304);
using DenseSlotMapHarness = SlotMapAdaptor<DenseSlotMap<MyComplexStruct>>;
using StableSlotMapHarness = SlotMapAdaptor<StableSlotMap<MyComplexStruct>>;
using UnorderedDenseMapHarness = HashMapHarnessAdaptor<ankerl::unordered_dense::map<std::uint64_t, MyComplexStruct>>;
using UnorderedDenseSegementedMapHarness =
HashMapHarnessAdaptor<ankerl::unordered_dense::segmented_map<std::uint64_t, MyComplexStruct>>;
using UnorderedMapHarness = HashMapHarnessAdaptor<std::unordered_map<std::uint64_t, MyComplexStruct>>;
using MapHarness = HashMapHarnessAdaptor<std::map<std::uint64_t, MyComplexStruct>>;
BIGFOOT_REGISTER_BENCHMARKS(SlotMapAdaptor, "Bigfoot::SlotMap");
BIGFOOT_REGISTER_BENCHMARKS(DenseSlotMapHarness, "Bigfoot::DenseSlotMap");
BIGFOOT_REGISTER_BENCHMARKS(StableSlotMapHarness, "Bigfoot::StableSlotMap");
BIGFOOT_REGISTER_BENCHMARKS(UnorderedDenseMapHarness, "ankerl::unordered_dense::map");
BIGFOOT_REGISTER_BENCHMARKS(UnorderedDenseSegementedMapHarness, "ankerl::unordered_dense::segmented_map");
BIGFOOT_REGISTER_BENCHMARKS(UnorderedMapHarness, "std::unordered_map");
@@ -0,0 +1,34 @@
/*********************************************************************
* \file Reference.cpp
*
* \author Romain BOULLARD
* \date July 2026
*********************************************************************/
#include <Engine/Asset/Reference.hpp>
#include <Engine/Asset/Reference_generated.hpp>
namespace flatbuffers
{
Flat::Bigfoot::AnyHardReference Pack(const ::Bigfoot::AnyHardReference& p_ref)
{
return {Pack(p_ref.GetUUID())};
}
::Bigfoot::AnyHardReference UnPack(const Flat::Bigfoot::AnyHardReference& p_ref)
{
return {UnPack(p_ref.uuid())};
}
/****************************************************************************************/
Flat::Bigfoot::AnySoftReference Pack(const ::Bigfoot::AnySoftReference& p_ref)
{
return {Pack(p_ref.GetUUID())};
}
::Bigfoot::AnySoftReference UnPack(const Flat::Bigfoot::AnySoftReference& p_ref)
{
return {UnPack(p_ref.uuid())};
}
} // namespace flatbuffers
@@ -17,21 +17,31 @@
namespace Bigfoot
{
class AssetBase
{
public:
virtual ~AssetBase() = default;
protected:
AssetBase() = default;
AssetBase(const AssetBase& p_asset) = default;
AssetBase(AssetBase&& p_asset) = default;
AssetBase& operator=(const AssetBase& p_asset) = default;
AssetBase& operator=(AssetBase&& p_asset) = default;
};
template<class ASSET>
class Asset
class Asset: public AssetBase
{
public:
using FLAT_ASSET = typename ASSET::FLAT;
Asset():
m_hardRefCount(0),
m_softRefCount(0),
m_header(::Flat::Bigfoot::AssetHeaderT {.uuid = UUID {},
.name = eastl::string {},
.type_id = GetTypeID(),
.type_name = eastl::string {GetTypeName()},
.version = 0})
Asset()
{
m_header.type_id = GetTypeID();
m_header.type_name = eastl::string {GetTypeName()};
}
explicit Asset(const eastl::span<const std::byte> p_flatbuffer):
@@ -58,39 +68,7 @@ class Asset
Asset(const Asset& p_asset) = delete;
Asset(Asset&& p_asset) = default;
virtual ~Asset() = default;
void IncrementHardRefCount()
{
m_hardRefCount++;
}
void DecrementHardRefCount()
{
m_hardRefCount--;
}
[[nodiscard]]
std::uint32_t GetHardRefCount() const
{
return m_hardRefCount;
}
void IncrementSoftRefCount()
{
m_softRefCount++;
}
void DecrementSoftRefCount()
{
m_hardRefCount--;
}
[[nodiscard]]
std::uint32_t GetSoftRefCount() const
{
return m_softRefCount;
}
~Asset() = default;
[[nodiscard]]
const ::Flat::Bigfoot::AssetHeaderT& GetHeader() const
@@ -98,6 +76,16 @@ class Asset
return m_header;
}
void SetName(const eastl::string_view p_name)
{
m_header.name = p_name;
}
void SetVersion(const std::uint32_t p_version)
{
m_header.version = p_version;
}
[[nodiscard]]
const typename FLAT_ASSET::NativeTableType& GetAsset() const
{
@@ -128,16 +116,6 @@ class Asset
std::bit_cast<std::byte*>(assetFbb.GetBufferPointer() + assetFbb.GetSize())};
}
void SetName(const eastl::string_view p_name)
{
m_header.name = p_name;
}
void SetVersion(const std::uint32_t p_version)
{
m_header.version = p_version;
}
[[nodiscard]]
static std::uint64_t GetTypeID()
{
@@ -156,11 +134,8 @@ class Asset
Asset& operator=(Asset&& p_asset) = default;
private:
std::uint32_t m_hardRefCount;
std::uint32_t m_softRefCount;
::Flat::Bigfoot::AssetHeaderT m_header;
typename FLAT_ASSET::NativeTableType m_asset;
::Flat::Bigfoot::AssetHeaderT m_header;
};
} // namespace Bigfoot
@@ -17,86 +17,159 @@
namespace Bigfoot
{
class ContainerHandle
{
public:
ContainerHandle() = default;
ContainerHandle(const ContainerHandle& p_handle) = default;
ContainerHandle(ContainerHandle&& p_handle) = default;
~ContainerHandle() = default;
void IncrementHardRefCount()
{
++m_hardRefCount;
}
void DecrementHardRefCount()
{
--m_hardRefCount;
}
void IncrementSoftRefCount()
{
++m_softRefCount;
}
void DecrementSoftRefCount()
{
--m_softRefCount;
}
[[nodiscard]]
AssetBase* GetAsset() const
{
return m_asset;
}
void SetAsset(AssetBase* p_asset)
{
m_asset = p_asset;
}
ContainerHandle& operator=(const ContainerHandle& p_handle) = default;
ContainerHandle& operator=(ContainerHandle&& p_handle) = default;
private:
std::uint32_t m_hardRefCount = 0;
std::uint32_t m_softRefCount = 0;
AssetBase* m_asset = nullptr;
};
class AssetContainerBase
{
public:
virtual ~AssetContainerBase() = default;
[[nodiscard]]
SlotMapKey GetAssetSlotKey(const UUID& p_uuid) const
{
if (const auto it = m_uuidToAssetSlotKey.find(p_uuid); it != m_uuidToAssetSlotKey.end())
{
return it->second;
}
return SlotMapKey {};
}
[[nodiscard]]
bool Has(const UUID& p_uuid) const
{
return m_uuidToAssetSlotKey.contains(p_uuid);
}
[[nodiscard]]
ContainerHandle& AcquireHandle(const UUID& p_uuid)
{
if (const auto it = m_uuidToContainerHandleSlotKey.find(p_uuid); it != m_uuidToContainerHandleSlotKey.end())
{
return *m_handles.Get(it->second);
}
const SlotMapKey key = m_handles.Insert();
m_uuidToContainerHandleSlotKey.insert({p_uuid, key});
return *m_handles.Get(key);
}
AssetContainerBase& operator=(const AssetContainerBase& p_container) = delete;
AssetContainerBase& operator=(AssetContainerBase&& p_container) = default;
protected:
AssetContainerBase() = default;
AssetContainerBase(const AssetContainerBase& p_container) = delete;
AssetContainerBase(AssetContainerBase&& p_container) = default;
ankerl::unordered_dense::segmented_map<UUID, SlotMapKey> m_uuidToAssetSlotKey;
ankerl::unordered_dense::segmented_map<UUID, SlotMapKey> m_uuidToContainerHandleSlotKey;
private:
StableSlotMap<ContainerHandle> m_handles;
};
template<class ASSET>
class AssetContainer
class AssetContainer: public AssetContainerBase
{
public:
AssetContainer() = default;
AssetContainer(const AssetContainer& p_container) = default;
AssetContainer(const AssetContainer& p_container) = delete;
AssetContainer(AssetContainer&& p_container) = default;
~AssetContainer() = default;
template<class... ARGS>
[[nodiscard]]
typename SlotMap<ASSET>::SlotKey Insert(ARGS&&... p_args)
SlotMapKey Insert(ARGS&&... p_args)
{
const typename SlotMap<ASSET>::SlotKey slotKey = m_assets.Insert(std::forward<ARGS>(p_args)...);
m_uuidToSlotKey.insert({m_assets.Get(slotKey)->GetHeader().uuid, slotKey});
const SlotMapKey slotKey = m_assets.Insert(std::forward<ARGS>(p_args)...);
ASSET* asset = m_assets.Get(slotKey);
m_uuidToAssetSlotKey.insert({asset->GetHeader().uuid, slotKey});
AcquireHandle(asset->GetHeader().uuid).SetAsset(asset);
return slotKey;
}
[[nodiscard]]
ASSET* Get(const typename SlotMap<ASSET>::SlotKey p_key)
ASSET* Get(const SlotMapKey p_key)
{
return m_assets.Get(p_key);
}
[[nodiscard]]
const ASSET* Get(const typename SlotMap<ASSET>::SlotKey p_key) const
const ASSET* Get(const SlotMapKey p_key) const
{
return m_assets.Get(p_key);
}
[[nodiscard]]
typename SlotMap<ASSET>::SlotKey GetSlotKey(const UUID& p_uuid) const
{
if (const auto it = m_uuidToSlotKey.find(p_uuid); it != m_uuidToSlotKey.end())
{
return it->second;
}
return typename SlotMap<ASSET>::SlotKey {};
}
[[nodiscard]]
bool Has(const typename SlotMap<ASSET>::SlotKey p_key) const
{
return m_assets.Has(p_key);
}
[[nodiscard]]
bool Has(const UUID& p_uuid) const
{
return m_uuidToSlotKey.contains(p_uuid);
}
void Remove(const typename SlotMap<ASSET>::SlotKey p_key)
{
if (const ASSET* asset = Get(p_key))
{
const UUID uuid = asset->GetHeader().uuid;
m_assets.Remove(p_key);
m_uuidToSlotKey.erase(uuid);
}
}
void Remove(const UUID& p_uuid)
{
if (const auto it = m_uuidToSlotKey.find(p_uuid); it != m_uuidToSlotKey.end())
if (const auto it = m_uuidToAssetSlotKey.find(p_uuid); it != m_uuidToAssetSlotKey.end())
{
Remove(it->second);
AcquireHandle(p_uuid).SetAsset(nullptr);
m_assets.Remove(it->second);
m_uuidToAssetSlotKey.erase(it->first);
}
}
AssetContainer& operator=(const AssetContainer& p_container) = default;
AssetContainer& operator=(const AssetContainer& p_container) = delete;
AssetContainer& operator=(AssetContainer&& p_container) = default;
private:
ankerl::unordered_dense::segmented_map<UUID, typename SlotMap<ASSET>::SlotKey> m_uuidToSlotKey;
SlotMap<ASSET> m_assets;
StableSlotMap<ASSET> m_assets;
};
} // namespace Bigfoot
@@ -8,10 +8,16 @@
#define BIGFOOT_ENGINE_ASSET_ASSETHELPER_HPP
#include <Engine/Asset/AssetContainer.hpp>
#include <Engine/Asset/AssetLibrary.hpp>
#include <Engine/Asset/Reference.hpp>
#define ASSET_CONTAINER(AssetName, AssetType) \
#define BIGFOOT_ASSET(AssetName, AssetType) \
namespace Bigfoot \
{ \
template<> \
AssetTypeID GetAssetTypeID<AssetType>() \
{ \
return AssetType::GetTypeID(); \
} \
AssetContainer<AssetType> g_containerFor##AssetName; \
const bool g_insertedContainerFor##AssetName = g_assetLibrary.Insert(&g_containerFor##AssetName); \
}
@@ -9,7 +9,6 @@
#include <Engine/Asset/AssetContainer.hpp>
#include <Engine/Asset/AssetTypeID.hpp>
#include <EASTL/any.h>
#include <ankerl/unordered_dense.h>
namespace Bigfoot
@@ -44,12 +43,7 @@ class AssetLibrary
AssetContainer<ASSET>* Get()
{
static const AssetTypeID typeID = ASSET::GetTypeID();
if (const auto container = m_assetContainers.find(typeID); container != m_assetContainers.end())
{
return eastl::any_cast<AssetContainer<ASSET>*>(container->second);
}
return nullptr;
return static_cast<AssetContainer<ASSET>*>(GetBase(typeID));
}
template<class ASSET>
@@ -57,9 +51,54 @@ class AssetLibrary
const AssetContainer<ASSET>* Get() const
{
static const AssetTypeID typeID = ASSET::GetTypeID();
if (const auto container = m_assetContainers.find(typeID); container != m_assetContainers.end())
return static_cast<const AssetContainer<ASSET>*>(GetBase(typeID));
}
[[nodiscard]]
AssetContainerBase* GetBase(const AssetTypeID p_typeID)
{
return eastl::any_cast<const AssetContainer<ASSET>*>(container->second);
if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end())
{
return container->second;
}
return nullptr;
}
[[nodiscard]]
const AssetContainerBase* GetBase(const AssetTypeID p_typeID) const
{
if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end())
{
return container->second;
}
return nullptr;
}
[[nodiscard]]
AssetContainerBase* FindContainer(const UUID& p_uuid)
{
for (const auto& [typeID, container]: m_assetContainers)
{
if (container->GetAssetSlotKey(p_uuid).Valid())
{
return container;
}
}
return nullptr;
}
[[nodiscard]]
const AssetContainerBase* FindContainer(const UUID& p_uuid) const
{
for (const auto& [typeID, container]: m_assetContainers)
{
if (container->GetAssetSlotKey(p_uuid).Valid())
{
return container;
}
}
return nullptr;
@@ -69,7 +108,7 @@ class AssetLibrary
AssetLibrary& operator=(AssetLibrary&& p_library) = default;
private:
ankerl::unordered_dense::segmented_map<AssetTypeID, eastl::any> m_assetContainers;
ankerl::unordered_dense::segmented_map<AssetTypeID, AssetContainerBase*> m_assetContainers;
};
inline AssetLibrary g_assetLibrary;
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "Engine/Asset/AssetTypeID.hpp"
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "Engine/Asset/AssetTypeID.hpp"
#include "System/UUID/UUID.hpp"
@@ -4,12 +4,22 @@ native_include "Engine/Asset/Reference.hpp";
namespace Flat.Bigfoot;
struct HardReference (native_type_template: "::Bigfoot::HardReference")
struct HardReference (bigfoot_ref_wrapper: "::Bigfoot::HardReference")
{
uuid: UUID;
}
struct SoftReference (native_type_template: "::Bigfoot::SoftReference")
struct SoftReference (bigfoot_ref_wrapper: "::Bigfoot::SoftReference")
{
uuid: UUID;
}
struct AnyHardReference (native_type: "::Bigfoot::AnyHardReference")
{
uuid: UUID;
}
struct AnySoftReference (native_type: "::Bigfoot::AnySoftReference")
{
uuid: UUID;
}
@@ -14,6 +14,9 @@
namespace Bigfoot
{
template<class ASSET>
AssetTypeID GetAssetTypeID();
template<class ASSET>
class HardReference
{
@@ -28,14 +31,14 @@ class HardReference
HardReference(const HardReference& p_ref):
m_uuid(p_ref.m_uuid),
m_slotKey(p_ref.m_slotKey)
m_handle(p_ref.m_handle)
{
Acquire();
}
HardReference(HardReference&& p_ref) noexcept:
m_uuid(std::exchange(p_ref.m_uuid, UUID::NULL_UUID)),
m_slotKey(std::exchange(p_ref.m_slotKey, typename SlotMap<ASSET>::SlotKey {}))
m_handle(std::exchange(p_ref.m_handle, nullptr))
{
}
@@ -45,6 +48,12 @@ class HardReference
return m_uuid;
}
[[nodiscard]]
ASSET* Get() const
{
return m_handle ? static_cast<ASSET*>(m_handle->GetAsset()) : nullptr;
}
~HardReference()
{
Release();
@@ -56,7 +65,7 @@ class HardReference
{
Release();
m_uuid = p_ref.m_uuid;
m_slotKey = p_ref.m_slotKey;
m_handle = p_ref.m_handle;
Acquire();
}
return *this;
@@ -68,7 +77,7 @@ class HardReference
{
Release();
m_uuid = std::exchange(p_ref.m_uuid, UUID::NULL_UUID);
std::exchange(p_ref.m_slotKey, typename SlotMap<ASSET>::SlotKey {});
m_handle = std::exchange(p_ref.m_handle, nullptr);
}
return *this;
}
@@ -82,34 +91,28 @@ class HardReference
private:
void Acquire()
{
if (AssetContainer<ASSET>* assetContainer = g_assetLibrary.Get<ASSET>(); assetContainer && m_uuid)
if (AssetContainerBase* assetContainer = g_assetLibrary.GetBase(GetAssetTypeID<ASSET>());
assetContainer && m_uuid)
{
if (!m_slotKey.Valid())
if (!m_handle)
{
m_slotKey = assetContainer->GetSlotKey(m_uuid);
}
if (ASSET* asset = assetContainer->Get(m_slotKey))
{
asset->IncrementHardRefCount();
m_handle = &assetContainer->AcquireHandle(m_uuid);
}
m_handle->IncrementHardRefCount();
}
}
void Release()
{
if (AssetContainer<ASSET>* assetContainer = g_assetLibrary.Get<ASSET>(); assetContainer && m_uuid)
if (m_handle)
{
// Acquire always happens before Release, so slot key should be valid
if (ASSET* asset = assetContainer->Get(m_slotKey))
{
asset->DecrementHardRefCount();
}
m_handle->DecrementHardRefCount();
m_handle = nullptr;
}
}
UUID m_uuid = UUID::NULL_UUID;
typename SlotMap<ASSET>::SlotKey m_slotKey;
ContainerHandle* m_handle = nullptr;
};
template<class ASSET>
@@ -126,14 +129,14 @@ class SoftReference
SoftReference(const SoftReference& p_ref):
m_uuid(p_ref.m_uuid),
m_slotKey(p_ref.m_slotKey)
m_handle(p_ref.m_handle)
{
Acquire();
}
SoftReference(SoftReference&& p_ref) noexcept:
m_uuid(std::exchange(p_ref.m_uuid, UUID::NULL_UUID)),
m_slotKey(std::exchange(p_ref.m_slotKey, typename SlotMap<ASSET>::SlotKey {}))
m_handle(std::exchange(p_ref.m_handle, nullptr))
{
}
@@ -143,6 +146,12 @@ class SoftReference
return m_uuid;
}
[[nodiscard]]
ASSET* Get() const
{
return m_handle ? static_cast<ASSET*>(m_handle->GetAsset()) : nullptr;
}
~SoftReference()
{
Release();
@@ -154,7 +163,7 @@ class SoftReference
{
Release();
m_uuid = p_ref.m_uuid;
m_slotKey = p_ref.m_slotKey;
m_handle = p_ref.m_handle;
Acquire();
}
return *this;
@@ -166,7 +175,7 @@ class SoftReference
{
Release();
m_uuid = std::exchange(p_ref.m_uuid, UUID::NULL_UUID);
m_slotKey = std::exchange(p_ref.m_slotKey, typename SlotMap<ASSET>::SlotKey {});
m_handle = std::exchange(p_ref.m_handle, nullptr);
}
return *this;
}
@@ -180,34 +189,231 @@ class SoftReference
private:
void Acquire()
{
if (AssetContainer<ASSET>* assetContainer = g_assetLibrary.Get<ASSET>(); assetContainer && m_uuid)
if (AssetContainerBase* assetContainer = g_assetLibrary.GetBase(GetAssetTypeID<ASSET>());
assetContainer && m_uuid)
{
if (!m_slotKey.Valid())
if (!m_handle)
{
m_slotKey = assetContainer->GetSlotKey(m_uuid);
}
if (ASSET* asset = assetContainer->Get(m_slotKey))
{
asset->IncrementSoftRefCount();
m_handle = &assetContainer->AcquireHandle(m_uuid);
}
m_handle->IncrementSoftRefCount();
}
}
void Release()
{
if (AssetContainer<ASSET>* assetContainer = g_assetLibrary.Get<ASSET>(); assetContainer && m_uuid)
if (m_handle)
{
// Acquire always happens before Release, so slot key should be valid
if (ASSET* asset = assetContainer->Get(m_slotKey))
{
asset->DecrementSoftRefCount();
}
m_handle->DecrementSoftRefCount();
m_handle = nullptr;
}
}
UUID m_uuid = UUID::NULL_UUID;
typename SlotMap<ASSET>::SlotKey m_slotKey;
ContainerHandle* m_handle = nullptr;
};
class AnyHardReference
{
public:
AnyHardReference() = default;
AnyHardReference(const UUID& p_uuid):
m_uuid(p_uuid)
{
Acquire();
}
AnyHardReference(const AnyHardReference& p_ref):
m_uuid(p_ref.m_uuid),
m_handle(p_ref.m_handle)
{
Acquire();
}
AnyHardReference(AnyHardReference&& p_ref) noexcept:
m_uuid(std::exchange(p_ref.m_uuid, UUID::NULL_UUID)),
m_handle(std::exchange(p_ref.m_handle, nullptr))
{
}
[[nodiscard]]
const UUID& GetUUID() const
{
return m_uuid;
}
~AnyHardReference()
{
Release();
}
AnyHardReference& operator=(const AnyHardReference& p_ref)
{
if (this != &p_ref)
{
Release();
m_uuid = p_ref.m_uuid;
m_handle = p_ref.m_handle;
Acquire();
}
return *this;
}
AnyHardReference& operator=(AnyHardReference&& p_ref) noexcept
{
if (this != &p_ref)
{
Release();
m_uuid = std::exchange(p_ref.m_uuid, UUID::NULL_UUID);
m_handle = std::exchange(p_ref.m_handle, nullptr);
}
return *this;
}
[[nodiscard]]
bool operator==(const AnyHardReference& p_ref) const
{
return m_uuid == p_ref.m_uuid;
}
private:
void Acquire()
{
if (AssetContainerBase* assetContainer = g_assetLibrary.FindContainer(m_uuid); assetContainer && m_uuid)
{
if (!m_handle)
{
m_handle = &assetContainer->AcquireHandle(m_uuid);
}
m_handle->IncrementHardRefCount();
}
}
void Release()
{
if (m_handle)
{
m_handle->DecrementHardRefCount();
m_handle = nullptr;
}
}
UUID m_uuid = UUID::NULL_UUID;
ContainerHandle* m_handle = nullptr;
};
class AnySoftReference
{
public:
AnySoftReference() = default;
AnySoftReference(const UUID& p_uuid):
m_uuid(p_uuid)
{
Acquire();
}
AnySoftReference(const AnySoftReference& p_ref):
m_uuid(p_ref.m_uuid),
m_handle(p_ref.m_handle)
{
Acquire();
}
AnySoftReference(AnySoftReference&& p_ref) noexcept:
m_uuid(std::exchange(p_ref.m_uuid, UUID::NULL_UUID)),
m_handle(std::exchange(p_ref.m_handle, nullptr))
{
}
[[nodiscard]]
const UUID& GetUUID() const
{
return m_uuid;
}
~AnySoftReference()
{
Release();
}
AnySoftReference& operator=(const AnySoftReference& p_ref)
{
if (this != &p_ref)
{
Release();
m_uuid = p_ref.m_uuid;
m_handle = p_ref.m_handle;
Acquire();
}
return *this;
}
AnySoftReference& operator=(AnySoftReference&& p_ref) noexcept
{
if (this != &p_ref)
{
Release();
m_uuid = std::exchange(p_ref.m_uuid, UUID::NULL_UUID);
m_handle = std::exchange(p_ref.m_handle, nullptr);
}
return *this;
}
[[nodiscard]]
bool operator==(const AnySoftReference& p_ref) const
{
return m_uuid == p_ref.m_uuid;
}
private:
void Acquire()
{
if (AssetContainerBase* assetContainer = g_assetLibrary.FindContainer(m_uuid); assetContainer && m_uuid)
{
if (!m_handle)
{
m_handle = &assetContainer->AcquireHandle(m_uuid);
}
m_handle->IncrementSoftRefCount();
}
}
void Release()
{
if (m_handle)
{
m_handle->DecrementSoftRefCount();
m_handle = nullptr;
}
}
UUID m_uuid = UUID::NULL_UUID;
ContainerHandle* m_handle = nullptr;
};
} // namespace Bigfoot
/****************************************************************************************/
namespace Flat
{
namespace Bigfoot
{
struct AnyHardReference;
struct AnySoftReference;
} // namespace Bigfoot
} // namespace Flat
/****************************************************************************************/
namespace flatbuffers
{
Flat::Bigfoot::AnyHardReference Pack(const ::Bigfoot::AnyHardReference& p_ref);
::Bigfoot::AnyHardReference UnPack(const Flat::Bigfoot::AnyHardReference& p_ref);
Flat::Bigfoot::AnySoftReference Pack(const ::Bigfoot::AnySoftReference& p_ref);
::Bigfoot::AnySoftReference UnPack(const Flat::Bigfoot::AnySoftReference& p_ref);
} // namespace flatbuffers
#endif
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "System/UUID/UUID.hpp"
#include "Engine/Asset/Reference.hpp"
@@ -28,10 +35,18 @@ struct HardReference;
struct SoftReference;
struct AnyHardReference;
struct AnySoftReference;
inline const ::flatbuffers::TypeTable *HardReferenceTypeTable();
inline const ::flatbuffers::TypeTable *SoftReferenceTypeTable();
inline const ::flatbuffers::TypeTable *AnyHardReferenceTypeTable();
inline const ::flatbuffers::TypeTable *AnySoftReferenceTypeTable();
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) HardReference FLATBUFFERS_FINAL_CLASS {
private:
Flat::Bigfoot::UUID uuid_;
@@ -88,6 +103,62 @@ struct SoftReference::Traits {
using type = SoftReference;
};
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) AnyHardReference FLATBUFFERS_FINAL_CLASS {
private:
Flat::Bigfoot::UUID uuid_;
public:
struct Traits;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return AnyHardReferenceTypeTable();
}
static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
return "Flat.Bigfoot.AnyHardReference";
}
AnyHardReference()
: uuid_() {
}
AnyHardReference(const Flat::Bigfoot::UUID &_uuid)
: uuid_(_uuid) {
}
const Flat::Bigfoot::UUID &uuid() const {
return uuid_;
}
};
FLATBUFFERS_STRUCT_END(AnyHardReference, 16);
struct AnyHardReference::Traits {
using type = AnyHardReference;
};
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) AnySoftReference FLATBUFFERS_FINAL_CLASS {
private:
Flat::Bigfoot::UUID uuid_;
public:
struct Traits;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return AnySoftReferenceTypeTable();
}
static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
return "Flat.Bigfoot.AnySoftReference";
}
AnySoftReference()
: uuid_() {
}
AnySoftReference(const Flat::Bigfoot::UUID &_uuid)
: uuid_(_uuid) {
}
const Flat::Bigfoot::UUID &uuid() const {
return uuid_;
}
};
FLATBUFFERS_STRUCT_END(AnySoftReference, 16);
struct AnySoftReference::Traits {
using type = AnySoftReference;
};
inline const ::flatbuffers::TypeTable *HardReferenceTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 }
@@ -116,6 +187,34 @@ inline const ::flatbuffers::TypeTable *SoftReferenceTypeTable() {
return &tt;
}
inline const ::flatbuffers::TypeTable *AnyHardReferenceTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
Flat::Bigfoot::UUIDTypeTable
};
static const int64_t values[] = { 0, 16 };
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 1, type_codes, type_refs, nullptr, values, nullptr
};
return &tt;
}
inline const ::flatbuffers::TypeTable *AnySoftReferenceTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
Flat::Bigfoot::UUIDTypeTable
};
static const int64_t values[] = { 0, 16 };
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 1, type_codes, type_refs, nullptr, values, nullptr
};
return &tt;
}
} // namespace Bigfoot
} // namespace Flat
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "System/Time/Time.hpp"
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "System/UUID/UUID.hpp"
File diff suppressed because it is too large Load Diff
@@ -12,6 +12,13 @@ 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"
-205
View File
@@ -1,205 +0,0 @@
/*********************************************************************
* \file BigFile.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <Engine/Asset/Asset.hpp>
#include <AssetsForTesting/Asset/AssetA.hpp>
#include <AssetsForTesting/Asset/AssetB.hpp>
#include <AssetsForTesting/Asset/AssetC.hpp>
#include <gtest/gtest.h>
namespace Bigfoot
{
class AssetFixture: public ::testing::Test
{
protected:
};
/****************************************************************************************/
TEST_F(AssetFixture, AssetATests)
{
constexpr eastl::string_view name = "Hello";
constexpr std::uint32_t version = 42;
constexpr std::uint32_t health = 100;
constexpr std::uint32_t mana = 50;
AssetA assetA;
assetA.SetName(name);
assetA.SetVersion(version);
assetA.GetAsset().health = health;
assetA.GetAsset().mana = mana;
const eastl::vector<std::byte> test = assetA.Save();
AssetA assetA_dup {test};
EXPECT_EQ(assetA.GetHeader().uuid, assetA_dup.GetHeader().uuid);
EXPECT_EQ(assetA.GetHeader().type_id, AssetA::GetTypeID());
EXPECT_EQ(assetA.GetHeader().type_id, assetA_dup.GetHeader().type_id);
EXPECT_EQ(assetA.GetHeader().type_name, AssetA::GetTypeName());
EXPECT_EQ(assetA.GetHeader().type_name, assetA_dup.GetHeader().type_name);
EXPECT_EQ(assetA.GetHeader().name, name);
EXPECT_EQ(assetA.GetHeader().name, assetA_dup.GetHeader().name);
EXPECT_EQ(assetA.GetHeader().version, version);
EXPECT_EQ(assetA.GetHeader().version, assetA_dup.GetHeader().version);
EXPECT_EQ(assetA.GetAsset().health, health);
EXPECT_EQ(assetA.GetAsset().health, assetA_dup.GetAsset().health);
EXPECT_EQ(assetA.GetAsset().mana, mana);
EXPECT_EQ(assetA.GetAsset().mana, assetA_dup.GetAsset().mana);
}
/****************************************************************************************/
TEST_F(AssetFixture, AssetBTests)
{
constexpr eastl::string_view nameA = "Hello";
constexpr std::uint32_t versionA = 42;
constexpr std::uint32_t healthA = 100;
constexpr std::uint32_t manaA = 50;
AssetA assetA;
assetA.SetName(nameA);
assetA.SetVersion(versionA);
assetA.GetAsset().health = healthA;
assetA.GetAsset().mana = manaA;
constexpr eastl::string_view nameAA = "There";
constexpr std::uint32_t versionAA = 42;
constexpr std::uint32_t healthAA = 100;
constexpr std::uint32_t manaAA = 50;
AssetA assetAA;
assetAA.SetName(nameAA);
assetAA.SetVersion(versionAA);
assetAA.GetAsset().health = healthAA;
assetAA.GetAsset().mana = manaAA;
constexpr eastl::string_view nameB = "Kenobi";
constexpr std::uint32_t versionB = 1;
AssetB assetB;
assetB.SetName(nameB);
assetB.SetVersion(versionB);
// assetB.GetAsset().asset_a_ref = HardReference<AssetA> {assetA.GetHeader().uuid};
// assetB.GetAsset().asset_a_refs = {SoftReference<AssetA> {assetA.GetHeader().uuid},
// SoftReference<AssetA> {assetAA.GetHeader().uuid}};
const eastl::vector<std::byte> test = assetB.Save();
AssetB assetB_dup {test};
EXPECT_EQ(assetB.GetHeader().uuid, assetB_dup.GetHeader().uuid);
EXPECT_EQ(assetB.GetHeader().type_id, AssetB::GetTypeID());
EXPECT_EQ(assetB.GetHeader().type_id, assetB_dup.GetHeader().type_id);
EXPECT_EQ(assetB.GetHeader().type_name, AssetB::GetTypeName());
EXPECT_EQ(assetB.GetHeader().type_name, assetB_dup.GetHeader().type_name);
EXPECT_EQ(assetB.GetHeader().name, nameB);
EXPECT_EQ(assetB.GetHeader().name, assetB_dup.GetHeader().name);
EXPECT_EQ(assetB.GetHeader().version, versionB);
EXPECT_EQ(assetB.GetHeader().version, assetB_dup.GetHeader().version);
// EXPECT_EQ(assetB.GetAsset().asset_a_ref, HardReference<AssetA> {assetA.GetHeader().uuid});
// EXPECT_EQ(assetB.GetAsset().asset_a_ref, assetB_dup.GetAsset().asset_a_ref);
// EXPECT_EQ(assetB.GetAsset().asset_a_refs,
// (eastl::vector<SoftReference<AssetA>> {SoftReference<AssetA> {assetA.GetHeader().uuid},
// SoftReference<AssetA> {assetAA.GetHeader().uuid}}));
// EXPECT_EQ(assetB.GetAsset().asset_a_refs, assetB_dup.GetAsset().asset_a_refs);
}
/****************************************************************************************/
TEST_F(AssetFixture, AssetCTests)
{
constexpr eastl::string_view nameA = "Hello";
constexpr std::uint32_t versionA = 42;
constexpr std::uint32_t healthA = 100;
constexpr std::uint32_t manaA = 50;
AssetA assetA;
assetA.SetName(nameA);
assetA.SetVersion(versionA);
assetA.GetAsset().health = healthA;
assetA.GetAsset().mana = manaA;
constexpr eastl::string_view nameAA = "There";
constexpr std::uint32_t versionAA = 42;
constexpr std::uint32_t healthAA = 100;
constexpr std::uint32_t manaAA = 50;
AssetA assetAA;
assetAA.SetName(nameAA);
assetAA.SetVersion(versionAA);
assetAA.GetAsset().health = healthAA;
assetAA.GetAsset().mana = manaAA;
constexpr eastl::string_view nameB = "Kenobi";
constexpr std::uint32_t versionB = 1;
AssetB assetB;
assetB.SetName(nameB);
assetB.SetVersion(versionB);
// assetB.GetAsset().asset_a_ref = HardReference<AssetA> {assetA.GetHeader().uuid};
// assetB.GetAsset().asset_a_refs = {SoftReference<AssetA> {assetA.GetHeader().uuid},
// SoftReference<AssetA> {assetAA.GetHeader().uuid}};
constexpr eastl::string_view nameC = "General";
constexpr std::uint32_t versionC = 1;
AssetC assetC;
assetC.SetName(nameC);
assetC.SetVersion(versionC);
// assetC.GetAsset().inner_table->asset_a_ref = HardReference<AssetA> {assetA.GetHeader().uuid};
// assetC.GetAsset().inner_table->asset_a_refs = {HardReference<AssetA> {assetA.GetHeader().uuid},
// HardReference<AssetA> {assetAA.GetHeader().uuid}};
// assetC.GetAsset().asset_b_ref = HardReference<AssetB> {assetB.GetHeader().uuid};
// assetC.GetAsset().asset_b_refs = {SoftReference<AssetB> {assetB.GetHeader().uuid}};
const eastl::vector<std::byte> test = assetC.Save();
AssetC assetC_dup {test};
EXPECT_EQ(assetC.GetHeader().uuid, assetC_dup.GetHeader().uuid);
EXPECT_EQ(assetC.GetHeader().type_id, AssetC::GetTypeID());
EXPECT_EQ(assetC.GetHeader().type_id, assetC_dup.GetHeader().type_id);
EXPECT_EQ(assetC.GetHeader().type_name, AssetC::GetTypeName());
EXPECT_EQ(assetC.GetHeader().type_name, assetC_dup.GetHeader().type_name);
EXPECT_EQ(assetC.GetHeader().name, nameC);
EXPECT_EQ(assetC.GetHeader().name, assetC_dup.GetHeader().name);
EXPECT_EQ(assetC.GetHeader().version, versionC);
EXPECT_EQ(assetC.GetHeader().version, assetC_dup.GetHeader().version);
// EXPECT_EQ(assetC.GetAsset().asset_b_ref, HardReference<AssetB> {assetB.GetHeader().uuid});
// EXPECT_EQ(assetC.GetAsset().asset_b_ref, assetC_dup.GetAsset().asset_b_ref);
// EXPECT_EQ(assetC.GetAsset().asset_b_refs,
// (eastl::vector<SoftReference<AssetB>> {SoftReference<AssetB> {assetB.GetHeader().uuid}}));
// EXPECT_EQ(assetC.GetAsset().asset_b_refs, assetC_dup.GetAsset().asset_b_refs);
// EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_ref, HardReference<AssetA> {assetA.GetHeader().uuid});
// EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_ref, assetC_dup.GetAsset().inner_table->asset_a_ref);
// EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_refs,
// (eastl::vector<HardReference<AssetA>> {HardReference<AssetA> {assetA.GetHeader().uuid},
// HardReference<AssetA> {assetAA.GetHeader().uuid}}));
// EXPECT_EQ(assetC.GetAsset().inner_table->asset_a_refs, assetC_dup.GetAsset().inner_table->asset_a_refs);
}
} // namespace Bigfoot
@@ -1,72 +0,0 @@
/*********************************************************************
* \file AssetContainer.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <Engine/Asset/AssetContainer.hpp>
#include <AssetsForTesting/Asset/AssetA.hpp>
#include <gtest/gtest.h>
namespace Bigfoot
{
class AssetContainerFixture: public ::testing::Test
{
protected:
AssetContainer<AssetA> m_container;
};
/****************************************************************************************/
TEST_F(AssetContainerFixture, Insert)
{
std::ignore = m_container.Insert();
}
/****************************************************************************************/
TEST_F(AssetContainerFixture, Get)
{
const auto key = m_container.Insert();
const auto& constContainer = m_container;
const auto validateKey = [&](auto& p_assetContainer)
{
const auto asset = p_assetContainer.Get(key);
EXPECT_NE(asset, nullptr);
};
validateKey(m_container);
validateKey(constContainer);
}
/****************************************************************************************/
TEST_F(AssetContainerFixture, GetSlotKey)
{
const auto key = m_container.Insert();
const auto asset = m_container.Get(key);
EXPECT_EQ(m_container.GetSlotKey(asset->GetHeader().uuid), key);
}
/****************************************************************************************/
TEST_F(AssetContainerFixture, Has)
{
const auto key = m_container.Insert();
EXPECT_TRUE(m_container.Has(key));
EXPECT_TRUE(m_container.Has(m_container.Get(key)->GetHeader().uuid));
}
/****************************************************************************************/
TEST_F(AssetContainerFixture, Remove)
{
const auto key1 = m_container.Insert();
m_container.Remove(key1);
const auto key2 = m_container.Insert();
m_container.Remove(m_container.Get(key2)->GetHeader().uuid);
}
} // namespace Bigfoot
@@ -1,74 +0,0 @@
/*********************************************************************
* \file AssetLibrary.cpp
*
* \author Romain BOULLARD
* \date July 2026
*********************************************************************/
#include <Engine/Asset/AssetLibrary.hpp>
#include <AssetsForTesting/Asset/AssetA.hpp>
#include <AssetsForTesting/Asset/AssetB.hpp>
#include <AssetsForTesting/Asset/AssetC.hpp>
#include <gtest/gtest.h>
namespace Bigfoot
{
class AssetLibraryFixture: public ::testing::Test
{
protected:
void SetUp() override
{
std::ignore = m_library.Insert(&m_containerA);
std::ignore = m_library.Insert(&m_containerB);
}
AssetContainer<AssetA> m_containerA;
AssetContainer<AssetB> m_containerB;
AssetLibrary m_library;
};
/****************************************************************************************/
TEST_F(AssetLibraryFixture, Insert_ShouldReturnTrueIfTheContainerHasBeenInserted)
{
AssetContainer<AssetC> containerC;
EXPECT_TRUE(m_library.Insert(&containerC));
}
/****************************************************************************************/
TEST_F(AssetLibraryFixture, Insert_ShouldReturnFalseIfTheContainerHasNotBeenInserted)
{
EXPECT_FALSE(m_library.Insert(&m_containerA)); // Duplicate
}
/****************************************************************************************/
TEST_F(AssetLibraryFixture, Get_ShouldReturnTheContainersIfTheyAreInTheLibrary)
{
const AssetContainer<AssetA>* containerA = m_library.Get<AssetA>();
const AssetContainer<AssetB>* containerB = m_library.Get<AssetB>();
EXPECT_EQ(&m_containerA, containerA);
EXPECT_EQ(&m_containerB, containerB);
}
/****************************************************************************************/
TEST_F(AssetLibraryFixture, Get_ShouldReturnNullptrIfTheContainersAreNotInTheLibrary)
{
const AssetContainer<AssetC>* containerC = m_library.Get<AssetC>();
EXPECT_EQ(nullptr, containerC);
}
/****************************************************************************************/
TEST_F(AssetLibraryFixture, GlobalAssetLibraryShouldHaveAssetsRegistered)
{
EXPECT_NE(g_assetLibrary.Get<AssetA>(), nullptr);
EXPECT_NE(g_assetLibrary.Get<AssetB>(), nullptr);
EXPECT_NE(g_assetLibrary.Get<AssetC>(), nullptr);
}
} // namespace Bigfoot
-147
View File
@@ -1,147 +0,0 @@
/*********************************************************************
* \file BigFile.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <Engine/BigFile/BigFile.hpp>
#include <System/Time/Time.hpp>
#include <System/UUID/UUID.hpp>
#include <EngineTests/BigFileInfo_generated.hpp>
#include <ankerl/unordered_dense.h>
#include <flatbuffers/reflection.h>
#include <gtest/gtest.h>
namespace Bigfoot
{
class BigFileFixture: public ::testing::Test
{
protected:
void SetUp() override
{
BigFile::Request deleteHeader {m_bigFile, "DELETE FROM AssetHeader"};
BigFile::Request deleteAsset {m_bigFile, "DELETE FROM Asset"};
m_bigFile.BeginTransaction();
deleteHeader.Execute();
deleteAsset.Execute();
m_bigFile.CommitTransaction();
}
BigFile m_bigFile {File {BIGFILE_ENGINETESTS_LOCATION}};
};
/****************************************************************************************/
TEST_F(BigFileFixture, BigFileManipulation)
{
UUID uuid;
UUID uuid2;
UUID uuid3;
constexpr eastl::array<std::byte, 4> blob {std::byte {1}, std::byte {2}, std::byte {3}, std::byte {4}};
constexpr eastl::array<std::byte, 4> blob2 {std::byte {1}, std::byte {2}, std::byte {3}, std::byte {5}};
constexpr eastl::array<std::byte, 4> blob3 {std::byte {1}, std::byte {2}, std::byte {3}, std::byte {6}};
constexpr eastl::array<std::byte, 4> blob4 {std::byte {10}, std::byte {11}, std::byte {12}, std::byte {13}};
constexpr std::uint64_t typeIDRef = std::numeric_limits<std::uint64_t>::max() - 1;
{
BigFile::Request assetHeaderRequest {
m_bigFile,
"INSERT INTO AssetHeader (UUID, Name, TypeID, TypeName) VALUES(?, ?, ?, ?)"};
assetHeaderRequest.Bind(1, uuid.ToBytes());
assetHeaderRequest.Bind(2, "Test");
assetHeaderRequest.Bind(3, typeIDRef);
assetHeaderRequest.Bind(4, "TypeTest");
BigFile::Request assetRequest {m_bigFile, "INSERT INTO Asset (UUID, Asset) VALUES(?, ?)"};
assetRequest.Bind(1, uuid.ToBytes());
assetRequest.Bind(2, blob);
BigFile::Request assetHeaderRequest2 {
m_bigFile,
"INSERT INTO AssetHeader (UUID, Name, TypeID, TypeName) VALUES(?, ?, ?, ?)"};
assetHeaderRequest2.Bind(1, uuid2.ToBytes());
assetHeaderRequest2.Bind(2, "Test2");
assetHeaderRequest2.Bind(3, typeIDRef);
assetHeaderRequest2.Bind(4, "TypeTest");
BigFile::Request assetRequest2 {m_bigFile, "INSERT INTO Asset (UUID, Asset) VALUES(?, ?)"};
assetRequest2.Bind(1, uuid2.ToBytes());
assetRequest2.Bind(2, blob3);
BigFile::Request assetHeaderRequest3 {
m_bigFile,
"INSERT INTO AssetHeader (UUID, Name, TypeID, TypeName) VALUES(?, ?, ?, ?)"};
assetHeaderRequest3.Bind(1, uuid3.ToBytes());
assetHeaderRequest3.Bind(2, "Test3");
assetHeaderRequest3.Bind(3, typeIDRef);
assetHeaderRequest3.Bind(4, "TypeTest");
BigFile::Request assetRequest3 {m_bigFile, "INSERT INTO Asset (UUID, Asset) VALUES(?, ?)"};
assetRequest3.Bind(1, uuid3.ToBytes());
assetRequest3.Bind(2, blob4);
m_bigFile.BeginTransaction();
std::uint32_t assetHeaderChangedCount = assetHeaderRequest.Execute();
EXPECT_EQ(assetHeaderChangedCount, 1);
std::uint32_t assetChangedCount = assetRequest.Execute();
EXPECT_EQ(assetChangedCount, 1);
std::uint32_t assetHeaderChangedCount2 = assetHeaderRequest2.Execute();
EXPECT_EQ(assetHeaderChangedCount2, 1);
std::uint32_t assetChangedCount2 = assetRequest2.Execute();
EXPECT_EQ(assetChangedCount2, 1);
std::uint32_t assetHeaderChangedCount3 = assetHeaderRequest3.Execute();
EXPECT_EQ(assetHeaderChangedCount3, 1);
std::uint32_t assetChangedCount3 = assetRequest3.Execute();
EXPECT_EQ(assetChangedCount3, 1);
m_bigFile.CommitTransaction();
}
{
BigFile::Request updateAsset {m_bigFile, "UPDATE Asset SET Asset = ? WHERE UUID = ?"};
updateAsset.Bind(1, blob2);
updateAsset.Bind(2, uuid.ToBytes());
m_bigFile.BeginTransaction();
std::uint32_t updateAssetChangedCount = updateAsset.Execute();
EXPECT_EQ(updateAssetChangedCount, 1);
m_bigFile.CommitTransaction();
}
{
BigFile::Request request {
m_bigFile,
"SELECT Name, TypeID, TypeName, CreateTime, ModificationTime FROM AssetHeader WHERE UUID = ?"};
request.Bind(1, uuid.ToBytes());
const bool get = request.Step();
EXPECT_TRUE(get);
const eastl::string name {static_cast<eastl::string_view>(request.Get(0))};
EXPECT_STREQ(name.c_str(), "Test");
const std::uint64_t typeID = static_cast<std::uint64_t>(request.Get(1));
EXPECT_EQ(typeID, typeIDRef);
const eastl::string typeName {static_cast<eastl::string_view>(request.Get(2))};
EXPECT_STREQ(typeName.c_str(), "TypeTest");
const Time createTime = static_cast<std::uint64_t>(request.Get(3));
const Time modificationTime = static_cast<std::uint64_t>(request.Get(4));
EXPECT_GT(createTime.GetEpoch(), 0);
EXPECT_GT(modificationTime.GetEpoch(), 0);
EXPECT_GE(createTime, modificationTime);
EXPECT_GT(createTime.GetYear(), 2025);
EXPECT_GT(modificationTime.GetYear(), 2025);
}
}
} // namespace Bigfoot
@@ -8,4 +8,4 @@
#include <Engine/Asset/AssetHelper.hpp>
ASSET_CONTAINER(AssetA, ::Bigfoot::AssetA)
BIGFOOT_ASSET(AssetA, ::Bigfoot::AssetA)
@@ -8,4 +8,4 @@
#include <Engine/Asset/AssetHelper.hpp>
ASSET_CONTAINER(AssetB, ::Bigfoot::AssetB)
BIGFOOT_ASSET(AssetB, ::Bigfoot::AssetB)
@@ -8,4 +8,4 @@
#include <Engine/Asset/AssetHelper.hpp>
ASSET_CONTAINER(AssetC, ::Bigfoot::AssetC)
BIGFOOT_ASSET(AssetC, ::Bigfoot::AssetC)
@@ -7,7 +7,7 @@ table AssetA
health: uint = 0;
mana: uint = 0;
ref_a: SoftReference (native_inline, native_type_template_arg: "::Bigfoot::AssetA");
ref_a: SoftReference (native_inline, bigfoot_ref: "::Bigfoot::AssetA");
}
root_type AssetA;
@@ -30,7 +30,7 @@ class AssetA: public Asset<AssetATraits>
AssetA(const AssetA& p_asset) = delete;
AssetA(AssetA&& p_asset) = default;
~AssetA() override = default;
~AssetA() = default;
AssetA& operator=(const AssetA& p_asset) = delete;
AssetA& operator=(AssetA&& p_asset) = default;
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "System/UUID/UUID.hpp"
#include "Engine/Asset/Reference.hpp"
@@ -28,6 +35,21 @@ struct AssetA;
struct AssetABuilder;
struct AssetAT;
} // namespace Bigfoot
} // namespace Flat
namespace Bigfoot {
class AssetA;
} // namespace Bigfoot
namespace flatbuffers {
Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset);
::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset);
} // namespace flatbuffers
namespace Flat {
namespace Bigfoot {
inline const ::flatbuffers::TypeTable *AssetATypeTable();
struct AssetAT : public ::flatbuffers::NativeTable {
@@ -218,4 +240,12 @@ inline eastl::unique_ptr<Flat::Bigfoot::AssetAT> UnPackSizePrefixedAssetA(
} // namespace Bigfoot
} // namespace Flat
namespace flatbuffers {
#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA
#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA
inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; }
inline ::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; }
#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA
} // namespace flatbuffers
#endif // FLATBUFFERS_GENERATED_ASSETA_FLAT_BIGFOOT_H_
@@ -4,8 +4,8 @@ namespace Flat.Bigfoot;
table AssetB
{
ref_a: HardReference (native_inline, native_type_template_arg: "::Bigfoot::AssetA");
refs_a: [SoftReference] (native_inline, native_type_template_arg: "::Bigfoot::AssetA");
ref_a: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetA");
refs_a: [SoftReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetA");
}
root_type AssetB;
@@ -30,7 +30,7 @@ class AssetB: public Asset<AssetBTraits>
AssetB(const AssetB& p_asset) = delete;
AssetB(AssetB&& p_asset) = default;
~AssetB() override = default;
~AssetB() = default;
AssetB& operator=(const AssetB& p_asset) = delete;
AssetB& operator=(AssetB&& p_asset) = default;
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "System/UUID/UUID.hpp"
#include "Engine/Asset/Reference.hpp"
@@ -28,6 +35,23 @@ struct AssetB;
struct AssetBBuilder;
struct AssetBT;
} // namespace Bigfoot
} // namespace Flat
namespace Bigfoot {
class AssetA;
} // namespace Bigfoot
namespace flatbuffers {
Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset);
::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset);
Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset);
::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset);
} // namespace flatbuffers
namespace Flat {
namespace Bigfoot {
inline const ::flatbuffers::TypeTable *AssetBTypeTable();
struct AssetBT : public ::flatbuffers::NativeTable {
@@ -205,4 +229,17 @@ inline eastl::unique_ptr<Flat::Bigfoot::AssetBT> UnPackSizePrefixedAssetB(
} // namespace Bigfoot
} // namespace Flat
namespace flatbuffers {
#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA
#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA
inline Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; }
inline ::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; }
#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA
#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA
#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA
inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; }
inline ::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; }
#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA
} // namespace flatbuffers
#endif // FLATBUFFERS_GENERATED_ASSETB_FLAT_BIGFOOT_H_
@@ -4,16 +4,19 @@ namespace Flat.Bigfoot;
table InnerTable
{
asset_a_ref: HardReference (native_inline, native_type_template_arg: "::Bigfoot::AssetA");
asset_a_refs: [HardReference] (native_inline, native_type_template_arg: "::Bigfoot::AssetA");
asset_a_ref: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetA");
asset_a_refs: [HardReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetA");
any_asset: AnyHardReference (native_inline);
any_assets: [AnySoftReference] (native_inline);
}
table AssetC
{
inner_table: InnerTable (required);
asset_b_ref: HardReference (native_inline, native_type_template_arg: "::Bigfoot::AssetB");
asset_b_refs: [SoftReference] (native_inline, native_type_template_arg: "::Bigfoot::AssetB");
asset_b_ref: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetB");
asset_b_refs: [SoftReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetB");
}
root_type AssetC;
@@ -33,7 +33,7 @@ class AssetC: public Asset<AssetCTraits>
AssetC(const AssetC& p_asset) = delete;
AssetC(AssetC&& p_asset) = default;
~AssetC() override = default;
~AssetC() = default;
AssetC& operator=(const AssetC& p_asset) = delete;
AssetC& operator=(AssetC&& p_asset) = default;
@@ -12,6 +12,13 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 12 &&
FLATBUFFERS_VERSION_REVISION == 19,
"Non-compatible flatbuffers version included");
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
#ifndef FLATBUFFERS_BIGFOOT_VERSION
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
#endif
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
"Non-compatible Bigfoot flatbuffers fork version included");
#include "System/UUID/UUID.hpp"
#include "Engine/Asset/Reference.hpp"
@@ -32,6 +39,29 @@ struct AssetC;
struct AssetCBuilder;
struct AssetCT;
} // namespace Bigfoot
} // namespace Flat
namespace Bigfoot {
class AssetA;
} // namespace Bigfoot
namespace Bigfoot {
class AssetB;
} // namespace Bigfoot
namespace flatbuffers {
Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset);
::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset);
Flat::Bigfoot::HardReference PackHardReferenceAssetB(const ::Bigfoot::HardReference<::Bigfoot::AssetB>& p_asset);
::Bigfoot::HardReference<::Bigfoot::AssetB> UnPackHardReferenceAssetB(const Flat::Bigfoot::HardReference& p_asset);
Flat::Bigfoot::SoftReference PackSoftReferenceAssetB(const ::Bigfoot::SoftReference<::Bigfoot::AssetB>& p_asset);
::Bigfoot::SoftReference<::Bigfoot::AssetB> UnPackSoftReferenceAssetB(const Flat::Bigfoot::SoftReference& p_asset);
} // namespace flatbuffers
namespace Flat {
namespace Bigfoot {
inline const ::flatbuffers::TypeTable *InnerTableTypeTable();
inline const ::flatbuffers::TypeTable *AssetCTypeTable();
@@ -43,6 +73,8 @@ struct InnerTableT : public ::flatbuffers::NativeTable {
}
::Bigfoot::HardReference<::Bigfoot::AssetA> asset_a_ref{};
eastl::vector<::Bigfoot::HardReference<::Bigfoot::AssetA>> asset_a_refs{};
::Bigfoot::AnyHardReference any_asset{};
eastl::vector<::Bigfoot::AnySoftReference> any_assets{};
};
struct InnerTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
@@ -57,7 +89,9 @@ struct InnerTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
}
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_ASSET_A_REF = 4,
VT_ASSET_A_REFS = 6
VT_ASSET_A_REFS = 6,
VT_ANY_ASSET = 8,
VT_ANY_ASSETS = 10
};
const Flat::Bigfoot::HardReference *asset_a_ref() const {
return GetStruct<const Flat::Bigfoot::HardReference *>(VT_ASSET_A_REF);
@@ -65,12 +99,21 @@ struct InnerTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
const ::flatbuffers::Vector<const Flat::Bigfoot::HardReference *> *asset_a_refs() const {
return GetPointer<const ::flatbuffers::Vector<const Flat::Bigfoot::HardReference *> *>(VT_ASSET_A_REFS);
}
const Flat::Bigfoot::AnyHardReference *any_asset() const {
return GetStruct<const Flat::Bigfoot::AnyHardReference *>(VT_ANY_ASSET);
}
const ::flatbuffers::Vector<const Flat::Bigfoot::AnySoftReference *> *any_assets() const {
return GetPointer<const ::flatbuffers::Vector<const Flat::Bigfoot::AnySoftReference *> *>(VT_ANY_ASSETS);
}
template <bool B = false>
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<Flat::Bigfoot::HardReference>(verifier, VT_ASSET_A_REF, 1) &&
VerifyOffset(verifier, VT_ASSET_A_REFS) &&
verifier.VerifyVector(asset_a_refs()) &&
VerifyField<Flat::Bigfoot::AnyHardReference>(verifier, VT_ANY_ASSET, 1) &&
VerifyOffset(verifier, VT_ANY_ASSETS) &&
verifier.VerifyVector(any_assets()) &&
verifier.EndTable();
}
InnerTableT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -88,6 +131,12 @@ struct InnerTableBuilder {
void add_asset_a_refs(::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> asset_a_refs) {
fbb_.AddOffset(InnerTable::VT_ASSET_A_REFS, asset_a_refs);
}
void add_any_asset(const Flat::Bigfoot::AnyHardReference *any_asset) {
fbb_.AddStruct(InnerTable::VT_ANY_ASSET, any_asset);
}
void add_any_assets(::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::AnySoftReference *>> any_assets) {
fbb_.AddOffset(InnerTable::VT_ANY_ASSETS, any_assets);
}
explicit InnerTableBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -102,8 +151,12 @@ struct InnerTableBuilder {
inline ::flatbuffers::Offset<InnerTable> CreateInnerTable(
::flatbuffers::FlatBufferBuilder &_fbb,
const Flat::Bigfoot::HardReference *asset_a_ref = nullptr,
::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> asset_a_refs = 0) {
::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> asset_a_refs = 0,
const Flat::Bigfoot::AnyHardReference *any_asset = nullptr,
::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::AnySoftReference *>> any_assets = 0) {
InnerTableBuilder builder_(_fbb);
builder_.add_any_assets(any_assets);
builder_.add_any_asset(any_asset);
builder_.add_asset_a_refs(asset_a_refs);
builder_.add_asset_a_ref(asset_a_ref);
return builder_.Finish();
@@ -224,6 +277,8 @@ inline void InnerTable::UnPackTo(InnerTableT *_o, const ::flatbuffers::resolver_
(void)_resolver;
{ auto _e = asset_a_ref(); if (_e) _o->asset_a_ref = ::flatbuffers::UnPackHardReferenceAssetA(*_e); }
{ auto _e = asset_a_refs(); if (_e) { _o->asset_a_refs.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->asset_a_refs[_i] = ::flatbuffers::UnPackHardReferenceAssetA(*_e->Get(_i)); } } else { _o->asset_a_refs.resize(0); } }
{ auto _e = any_asset(); if (_e) _o->any_asset = ::flatbuffers::UnPack(*_e); }
{ auto _e = any_assets(); if (_e) { _o->any_assets.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->any_assets[_i] = ::flatbuffers::UnPack(*_e->Get(_i)); } } else { _o->any_assets.resize(0); } }
}
inline ::flatbuffers::Offset<InnerTable> CreateInnerTable(::flatbuffers::FlatBufferBuilder &_fbb, const InnerTableT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
@@ -236,10 +291,14 @@ inline ::flatbuffers::Offset<InnerTable> InnerTable::Pack(::flatbuffers::FlatBuf
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const InnerTableT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _asset_a_ref = ::flatbuffers::PackHardReferenceAssetA(_o->asset_a_ref);
auto _asset_a_refs = _fbb.CreateVectorOfNativeStructs<Flat::Bigfoot::HardReference, ::Bigfoot::HardReference<::Bigfoot::AssetA>>(_o->asset_a_refs.data(), _o->asset_a_refs.size(), ::flatbuffers::PackHardReferenceAssetA);
auto _any_asset = ::flatbuffers::Pack(_o->any_asset);
auto _any_assets = _fbb.CreateVectorOfNativeStructs<Flat::Bigfoot::AnySoftReference, ::Bigfoot::AnySoftReference>(_o->any_assets.data(), _o->any_assets.size());
return Flat::Bigfoot::CreateInnerTable(
_fbb,
&_asset_a_ref,
_asset_a_refs);
_asset_a_refs,
&_any_asset,
_any_assets);
}
inline AssetCT::AssetCT(const AssetCT &o)
@@ -290,13 +349,17 @@ inline ::flatbuffers::Offset<AssetC> AssetC::Pack(::flatbuffers::FlatBufferBuild
inline const ::flatbuffers::TypeTable *InnerTableTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 1, 0 }
{ ::flatbuffers::ET_SEQUENCE, 1, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 1 },
{ ::flatbuffers::ET_SEQUENCE, 1, 2 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
Flat::Bigfoot::HardReferenceTypeTable
Flat::Bigfoot::HardReferenceTypeTable,
Flat::Bigfoot::AnyHardReferenceTypeTable,
Flat::Bigfoot::AnySoftReferenceTypeTable
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, nullptr, nullptr
::flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, nullptr, nullptr
};
return &tt;
}
@@ -369,4 +432,22 @@ inline eastl::unique_ptr<Flat::Bigfoot::AssetCT> UnPackSizePrefixedAssetC(
} // namespace Bigfoot
} // namespace Flat
namespace flatbuffers {
#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA
#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA
inline Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; }
inline ::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; }
#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA
#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETB
#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETB
inline Flat::Bigfoot::HardReference PackHardReferenceAssetB(const ::Bigfoot::HardReference<::Bigfoot::AssetB>& p_asset) { return {Pack(p_asset.GetUUID())}; }
inline ::Bigfoot::HardReference<::Bigfoot::AssetB> UnPackHardReferenceAssetB(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; }
#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETB
#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETB
#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETB
inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetB(const ::Bigfoot::SoftReference<::Bigfoot::AssetB>& p_asset) { return {Pack(p_asset.GetUUID())}; }
inline ::Bigfoot::SoftReference<::Bigfoot::AssetB> UnPackSoftReferenceAssetB(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; }
#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETB
} // namespace flatbuffers
#endif // FLATBUFFERS_GENERATED_ASSETC_FLAT_BIGFOOT_H_
-537
View File
@@ -1,537 +0,0 @@
/*********************************************************************
* \file SlotMap.cpp
*
* \author Romain BOULLARD
* \date May 2026
*********************************************************************/
#include <Utils/Containers/SlotMap.hpp>
#include <gtest/gtest.h>
namespace Bigfoot
{
template<class VERSION_TYPE, class INDEX_TYPE>
struct SlotMapConfig
{
using Version = VERSION_TYPE;
using Index = INDEX_TYPE;
};
using SlotMapConfigs = ::testing::Types<SlotMapConfig<std::uint8_t, std::uint8_t>,
SlotMapConfig<std::uint8_t, std::uint16_t>,
SlotMapConfig<std::uint8_t, std::uint32_t>,
SlotMapConfig<std::uint16_t, std::uint8_t>,
SlotMapConfig<std::uint16_t, std::uint16_t>,
SlotMapConfig<std::uint16_t, std::uint32_t>,
SlotMapConfig<std::uint32_t, std::uint8_t>,
SlotMapConfig<std::uint32_t, std::uint16_t>,
SlotMapConfig<std::uint32_t, std::uint32_t>>;
struct SlotMapConfigNames
{
template<class T>
static std::string GetName(int)
{
return "VERSION" + std::to_string(sizeof(typename T::Version) * 8) + "_INDEX" +
std::to_string(sizeof(typename T::Index) * 8);
}
};
/****************************************************************************************/
template<class CONFIG>
class SlotKeyFixture: public ::testing::Test
{
protected:
using SlotMapVersion = typename CONFIG::Version;
using SlotMapIndex = typename CONFIG::Index;
using SlotMapType = SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>;
using SlotKey = typename SlotMapType::SlotKey;
};
TYPED_TEST_SUITE(SlotKeyFixture, SlotMapConfigs, SlotMapConfigNames);
/****************************************************************************************/
TYPED_TEST(SlotKeyFixture, DefaultSlotKeyIsInvalid)
{
constexpr typename TestFixture::SlotMapIndex index = 0;
constexpr typename TestFixture::SlotMapVersion version = 0;
constexpr typename TestFixture::SlotKey slotKey {};
EXPECT_FALSE(slotKey.Valid());
EXPECT_EQ(slotKey.GetVersion(), version);
EXPECT_EQ(slotKey.GetIndex(), index);
}
/****************************************************************************************/
TYPED_TEST(SlotKeyFixture, Valid_ShouldReturnTrueIfTheSlotKeyIsValid)
{
constexpr typename TestFixture::SlotMapIndex index = 0;
constexpr typename TestFixture::SlotMapVersion version = 1;
constexpr typename TestFixture::SlotKey slotKey {version, index};
EXPECT_TRUE(slotKey.Valid());
}
/****************************************************************************************/
TYPED_TEST(SlotKeyFixture, Valid_ShouldReturnFalseIfTheSlotKeyIsValid)
{
constexpr typename TestFixture::SlotMapIndex index = 0;
constexpr typename TestFixture::SlotMapVersion version = 0;
constexpr typename TestFixture::SlotKey slotKey {version, index};
EXPECT_FALSE(slotKey.Valid());
}
/****************************************************************************************/
TYPED_TEST(SlotKeyFixture, GetVersion_ShouldReturnTheVersion)
{
constexpr typename TestFixture::SlotMapIndex index = 0;
constexpr typename TestFixture::SlotMapVersion version = 42;
constexpr typename TestFixture::SlotKey slotKey {version, index};
EXPECT_EQ(slotKey.GetVersion(), version);
}
/****************************************************************************************/
TYPED_TEST(SlotKeyFixture, GetIndex_ShouldReturnTheIndex)
{
constexpr typename TestFixture::SlotMapIndex index = 42;
constexpr typename TestFixture::SlotMapVersion version = 0;
constexpr typename TestFixture::SlotKey slotKey {version, index};
EXPECT_EQ(slotKey.GetIndex(), index);
}
/****************************************************************************************/
template<class CONFIG>
class SlotMapFixture: public ::testing::Test
{
protected:
using SlotMapVersion = typename CONFIG::Version;
using SlotMapIndex = typename CONFIG::Index;
using SlotMapType = SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>;
using SlotKey = typename SlotMapType::SlotKey;
SlotMapType m_slotMap;
};
TYPED_TEST_SUITE(SlotMapFixture, SlotMapConfigs, SlotMapConfigNames);
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Insert_ShouldReturnAValidSlotKey)
{
const auto slotKey = this->m_slotMap.Insert(42);
EXPECT_TRUE(slotKey.Valid());
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Insert_ShouldRecycleASlotKeyAfterARemove)
{
const auto slotKey = this->m_slotMap.Insert(42);
this->m_slotMap.Remove(slotKey);
const auto secondSlotKey = this->m_slotMap.Insert(69);
EXPECT_NE(secondSlotKey.GetVersion(), slotKey.GetVersion());
EXPECT_EQ(secondSlotKey.GetIndex(), slotKey.GetIndex());
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Has_ShouldReturnTrueIfTheSlotMapHasTheKey)
{
const auto slotKey = this->m_slotMap.Insert(42);
EXPECT_TRUE(this->m_slotMap.Has(slotKey));
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Has_ShouldReturnFalseIfTheSlotMapDoesNotHaveTheKey)
{
const auto slotKey = this->m_slotMap.Insert(42);
this->m_slotMap.Remove(slotKey);
EXPECT_FALSE(this->m_slotMap.Has(slotKey));
EXPECT_FALSE(this->m_slotMap.Has(typename TestFixture::SlotKey {1, 22}));
EXPECT_FALSE(this->m_slotMap.Has(typename TestFixture::SlotKey {}));
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Remove_ShouldRemoveTheSlotKey)
{
const auto slotKey = this->m_slotMap.Insert(42);
this->m_slotMap.Remove(slotKey);
EXPECT_FALSE(this->m_slotMap.Has(slotKey));
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Remove_ShouldNotRecycleASlotWhenVersionWasExhausted)
{
if constexpr (std::is_same_v<typename TestFixture::SlotMapVersion, std::uint32_t>)
{
GTEST_SKIP() << "Skipped for 32-bit version: exhausting all versions is too slow.";
}
else
{
auto key = this->m_slotMap.Insert(1);
for (typename TestFixture::SlotMapVersion i = 1;
i < std::numeric_limits<typename TestFixture::SlotMapVersion>::max();
++i)
{
this->m_slotMap.Remove(key);
const auto newKey = this->m_slotMap.Insert(1);
EXPECT_EQ(newKey.GetIndex(), key.GetIndex());
key = newKey;
}
// Slot is at MAX_VERSION — one more remove should overflow and permanently deactivate it
EXPECT_EQ(key.GetVersion(), std::numeric_limits<typename TestFixture::SlotMapVersion>::max());
this->m_slotMap.Remove(key);
EXPECT_FALSE(this->m_slotMap.Has(key));
// Dead slot must not be recycled; a new insert must allocate a fresh slot index
const auto newKey = this->m_slotMap.Insert(2);
EXPECT_NE(newKey.GetIndex(), key.GetIndex());
// Ensure an invalid key does not return an exhausted slot
EXPECT_EQ(this->m_slotMap.Get(typename TestFixture::SlotKey {}), nullptr);
}
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Remove_ShouldNotDoAnythingInCaseOfDoubleRemove)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
this->m_slotMap.Remove(slotKey1);
this->m_slotMap.Remove(slotKey1);
EXPECT_EQ(*this->m_slotMap.Get(slotKey2), 69);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Remove_ShouldNotDoAnythingInCaseStaleKey)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
this->m_slotMap.Remove(typename TestFixture::SlotKey {2, 0});
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 42);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Get_ShouldReturnNullptrForInvalidSlotKeys)
{
const auto slotKey = this->m_slotMap.Insert(42);
this->m_slotMap.Remove(slotKey);
const auto validate = [&](auto& p_slotMap)
{
EXPECT_EQ(p_slotMap.Get(slotKey), nullptr);
EXPECT_EQ(p_slotMap.Get(typename TestFixture::SlotKey {1, 3}), nullptr);
EXPECT_EQ(p_slotMap.Get(typename TestFixture::SlotKey {}), nullptr);
};
validate(this->m_slotMap);
const auto& constSlotMap = this->m_slotMap;
validate(constSlotMap);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Get_ShouldReturnTheValueForValidSlotKeys)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
const auto slotKey3 = this->m_slotMap.Insert(28);
const auto slotKey4 = this->m_slotMap.Insert(0);
this->m_slotMap.Remove(slotKey2);
const auto validate = [&](auto& p_slotMap)
{
EXPECT_EQ(*p_slotMap.Get(slotKey1), 42);
EXPECT_EQ(*p_slotMap.Get(slotKey3), 28);
EXPECT_EQ(*p_slotMap.Get(slotKey4), 0);
};
validate(this->m_slotMap);
const auto& constSlotMap = this->m_slotMap;
validate(constSlotMap);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Reset_ResetsTheSlotMapAndMakesCollisionWithOldSlotKeys)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
this->m_slotMap.Reset();
const auto slotKey5 = this->m_slotMap.Insert(128);
EXPECT_EQ(slotKey1, slotKey5);
EXPECT_EQ(*this->m_slotMap.Get(slotKey5), 128);
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 128);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Clear_ResetsTheSlotMapAndButGuaranteesNotCollisionWithOldSlotKeys)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
this->m_slotMap.Clear();
const auto slotKey5 = this->m_slotMap.Insert(128);
EXPECT_NE(slotKey1, slotKey5);
EXPECT_EQ(*this->m_slotMap.Get(slotKey5), 128);
EXPECT_EQ(this->m_slotMap.Get(slotKey1), nullptr);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, GetSize_ReturnTheSizeOfTheSlotMap)
{
EXPECT_EQ(this->m_slotMap.GetSize(), 0);
std::ignore = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
EXPECT_EQ(this->m_slotMap.GetSize(), 4);
this->m_slotMap.Remove(slotKey2);
EXPECT_EQ(this->m_slotMap.GetSize(), 3);
this->m_slotMap.Clear();
EXPECT_EQ(this->m_slotMap.GetSize(), 0);
std::ignore = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
EXPECT_EQ(this->m_slotMap.GetSize(), 4);
this->m_slotMap.Reset();
EXPECT_EQ(this->m_slotMap.GetSize(), 0);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Empty_ShouldReturnTrueIfTheSlotMapIsEmpty)
{
EXPECT_TRUE(this->m_slotMap.Empty());
std::ignore = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
this->m_slotMap.Clear();
EXPECT_TRUE(this->m_slotMap.Empty());
std::ignore = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
this->m_slotMap.Reset();
EXPECT_TRUE(this->m_slotMap.Empty());
const auto slotKey9 = this->m_slotMap.Insert(42);
this->m_slotMap.Remove(slotKey9);
EXPECT_TRUE(this->m_slotMap.Empty());
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Empty_ShouldReturnFalseIfTheSlotMapIsNotEmpty)
{
std::ignore = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
EXPECT_FALSE(this->m_slotMap.Empty());
this->m_slotMap.Clear();
std::ignore = this->m_slotMap.Insert(42);
std::ignore = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
EXPECT_FALSE(this->m_slotMap.Empty());
this->m_slotMap.Reset();
const auto slotKey9 = this->m_slotMap.Insert(42);
EXPECT_FALSE(this->m_slotMap.Empty());
this->m_slotMap.Remove(slotKey9);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, Iterator)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
const auto slotKey3 = this->m_slotMap.Insert(28);
const auto slotKey4 = this->m_slotMap.Insert(0);
this->m_slotMap.Remove(slotKey2);
eastl::vector<std::uint32_t> values;
for (auto it = this->m_slotMap.begin(); it != this->m_slotMap.end(); ++it)
{
values.push_back(*it);
}
ASSERT_EQ(values.size(), 3);
EXPECT_EQ(values[0], 42);
EXPECT_EQ(values[1], 0);
EXPECT_EQ(values[2], 28);
// The non-const iterator is mutable.
for (std::uint32_t& value: this->m_slotMap)
{
value += 100;
}
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 142);
EXPECT_EQ(*this->m_slotMap.Get(slotKey3), 128);
EXPECT_EQ(*this->m_slotMap.Get(slotKey4), 100);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, ConstIterator)
{
std::ignore = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
this->m_slotMap.Remove(slotKey2);
const auto& constSlotMap = this->m_slotMap;
eastl::vector<std::uint32_t> values;
for (auto it = constSlotMap.begin(); it != constSlotMap.end(); ++it)
{
values.push_back(*it);
}
ASSERT_EQ(values.size(), 3);
EXPECT_EQ(values[0], 42);
EXPECT_EQ(values[1], 0);
EXPECT_EQ(values[2], 28);
// cbegin/cend yield the same const traversal.
eastl::vector<std::uint32_t> cValues;
for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it)
{
cValues.push_back(*it);
}
EXPECT_EQ(values, cValues);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, ReverseIterator)
{
const auto slotKey1 = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
const auto slotKey3 = this->m_slotMap.Insert(28);
const auto slotKey4 = this->m_slotMap.Insert(0);
this->m_slotMap.Remove(slotKey2);
eastl::vector<std::uint32_t> values;
for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it)
{
values.push_back(*it);
}
ASSERT_EQ(values.size(), 3);
EXPECT_EQ(values[0], 28);
EXPECT_EQ(values[1], 0);
EXPECT_EQ(values[2], 42);
// The non-const reverse iterator is mutable.
for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it)
{
*it += 100;
}
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 142);
EXPECT_EQ(*this->m_slotMap.Get(slotKey3), 128);
EXPECT_EQ(*this->m_slotMap.Get(slotKey4), 100);
}
/****************************************************************************************/
TYPED_TEST(SlotMapFixture, ConstReverseIterator)
{
std::ignore = this->m_slotMap.Insert(42);
const auto slotKey2 = this->m_slotMap.Insert(69);
std::ignore = this->m_slotMap.Insert(28);
std::ignore = this->m_slotMap.Insert(0);
this->m_slotMap.Remove(slotKey2);
const auto& constSlotMap = this->m_slotMap;
eastl::vector<std::uint32_t> values;
for (auto it = constSlotMap.rbegin(); it != constSlotMap.rend(); ++it)
{
values.push_back(*it);
}
ASSERT_EQ(values.size(), 3);
EXPECT_EQ(values[0], 28);
EXPECT_EQ(values[1], 0);
EXPECT_EQ(values[2], 42);
// crbegin/crend yield the same const reverse traversal.
eastl::vector<std::uint32_t> crValues;
for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it)
{
crValues.push_back(*it);
}
EXPECT_EQ(values, crValues);
}
} // namespace Bigfoot