AssetContainer tests
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 2s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Failing after 2s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Failing after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 1s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Failing after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Failing after 1s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Failing after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Failing after 0s
Bigfoot / Clang Format Checks (push) Failing after 1m44s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 2s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Failing after 2s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Failing after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 1s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Failing after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Failing after 1s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Failing after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Failing after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Failing after 0s
Bigfoot / Clang Format Checks (push) Failing after 1m44s
This commit is contained in:
@@ -27,38 +27,69 @@ class ContainerHandle
|
||||
|
||||
~ContainerHandle() = default;
|
||||
|
||||
/*
|
||||
* Increment the HardRef count
|
||||
*
|
||||
*/
|
||||
void IncrementHardRefCount()
|
||||
{
|
||||
++m_hardRefCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the HardRef count
|
||||
*
|
||||
*/
|
||||
void DecrementHardRefCount()
|
||||
{
|
||||
--m_hardRefCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment the SoftRef count
|
||||
*
|
||||
*/
|
||||
void IncrementSoftRefCount()
|
||||
{
|
||||
++m_softRefCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the SoftRef count
|
||||
*
|
||||
*/
|
||||
void DecrementSoftRefCount()
|
||||
{
|
||||
--m_softRefCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the Asset
|
||||
*
|
||||
* \return The asset, can be nullptr
|
||||
*/
|
||||
[[nodiscard]]
|
||||
AssetBase* GetAsset()
|
||||
{
|
||||
return m_asset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the Asset
|
||||
*
|
||||
* \return The asset
|
||||
*/
|
||||
[[nodiscard]]
|
||||
const AssetBase* GetAsset() const
|
||||
{
|
||||
return m_asset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the asset
|
||||
*
|
||||
* \param p_asset The asset
|
||||
*/
|
||||
void SetAsset(AssetBase* p_asset)
|
||||
{
|
||||
m_asset = p_asset;
|
||||
@@ -68,8 +99,19 @@ class ContainerHandle
|
||||
ContainerHandle& operator=(ContainerHandle&& p_handle) = default;
|
||||
|
||||
private:
|
||||
/*
|
||||
* The HardRef count
|
||||
*/
|
||||
std::uint32_t m_hardRefCount = 0;
|
||||
|
||||
/*
|
||||
* The SoftRef count
|
||||
*/
|
||||
std::uint32_t m_softRefCount = 0;
|
||||
|
||||
/*
|
||||
* The asset
|
||||
*/
|
||||
AssetBase* m_asset = nullptr;
|
||||
};
|
||||
|
||||
@@ -80,51 +122,135 @@ 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 {};
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an Asset is in the AssetContainer or not
|
||||
*
|
||||
* \param p_uuid The UUID to check
|
||||
* \return True if in AssetContainer, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool Has(const UUID& p_uuid) const
|
||||
{
|
||||
return m_uuidToAssetSlotKey.contains(p_uuid);
|
||||
const Entry* entry = FindEntry(p_uuid);
|
||||
return entry != nullptr && entry->m_assetSlotKey.Valid();
|
||||
}
|
||||
|
||||
/*
|
||||
* Acquires a ContainerHandle for a given UUID
|
||||
* Will create it if it does not exists
|
||||
*
|
||||
* \param p_uuid The UUID to get ContainerHandle for
|
||||
* \return A ContainerHandle for the UUID
|
||||
*/
|
||||
[[nodiscard]]
|
||||
ContainerHandle& AcquireHandle(const UUID& p_uuid)
|
||||
ContainerHandle& AcquireContainerHandle(const UUID& p_uuid)
|
||||
{
|
||||
if (const auto it = m_uuidToContainerHandleSlotKey.find(p_uuid); it != m_uuidToContainerHandleSlotKey.end())
|
||||
return *m_handles.Get(GetOrCreateEntry(p_uuid).m_handleSlotKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an Asset from the AssetContainer
|
||||
*
|
||||
* \param p_uuid The UUID to remove
|
||||
*/
|
||||
virtual void Remove(const UUID& p_uuid)
|
||||
{
|
||||
if (Entry* entry = FindEntry(p_uuid); entry != nullptr && entry->m_handleSlotKey.Valid())
|
||||
{
|
||||
return *m_handles.Get(it->second);
|
||||
m_handles.Remove(entry->m_handleSlotKey);
|
||||
m_uuidToEntry.erase(p_uuid);
|
||||
}
|
||||
|
||||
const SlotMapKey key = m_handles.Insert();
|
||||
m_uuidToContainerHandleSlotKey.emplace(p_uuid, key);
|
||||
|
||||
return *m_handles.Get(key);
|
||||
}
|
||||
|
||||
AssetContainerBase& operator=(const AssetContainerBase& p_container) = delete;
|
||||
AssetContainerBase& operator=(AssetContainerBase&& p_container) = default;
|
||||
|
||||
protected:
|
||||
struct Entry
|
||||
{
|
||||
/*
|
||||
* SlotMapKey to the handle
|
||||
*/
|
||||
SlotMapKey m_handleSlotKey;
|
||||
|
||||
/*
|
||||
* SlotMapKey to the asset
|
||||
*/
|
||||
SlotMapKey m_assetSlotKey;
|
||||
};
|
||||
|
||||
AssetContainerBase() = default;
|
||||
|
||||
AssetContainerBase(const AssetContainerBase& p_container) = delete;
|
||||
AssetContainerBase(AssetContainerBase&& p_container) = default;
|
||||
|
||||
ankerl::unordered_dense::segmented_map<UUID, SlotMapKey> m_uuidToAssetSlotKey;
|
||||
ankerl::unordered_dense::segmented_map<UUID, SlotMapKey> m_uuidToContainerHandleSlotKey;
|
||||
/*
|
||||
* Finds an entry matching the Asset
|
||||
*
|
||||
* \param p_uuid The UUID to find
|
||||
* \return Pointer to an Entry, nullptr otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
Entry* FindEntry(const UUID& p_uuid)
|
||||
{
|
||||
const auto it = m_uuidToEntry.find(p_uuid);
|
||||
return it != m_uuidToEntry.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds an entry matching the Asset
|
||||
*
|
||||
* \param p_uuid The UUID to find
|
||||
* \return Pointer to an Entry, nullptr otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
const Entry* FindEntry(const UUID& p_uuid) const
|
||||
{
|
||||
const auto it = m_uuidToEntry.find(p_uuid);
|
||||
return it != m_uuidToEntry.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds an entry matching the Asset
|
||||
* Creates it if it does not exist
|
||||
*
|
||||
* \param p_uuid The UUID to find
|
||||
* \return The entry matching the Asset
|
||||
*/
|
||||
[[nodiscard]]
|
||||
Entry& GetOrCreateEntry(const UUID& p_uuid)
|
||||
{
|
||||
auto [it, inserted] = m_uuidToEntry.try_emplace(p_uuid);
|
||||
if (inserted)
|
||||
{
|
||||
it->second.m_handleSlotKey = m_handles.Insert();
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a ContainerHandle
|
||||
*
|
||||
* \param p_handleSlotKey The key to the container
|
||||
* \return The container
|
||||
*/
|
||||
[[nodiscard]]
|
||||
ContainerHandle& FindContainerHandle(const SlotMapKey p_handleSlotKey)
|
||||
{
|
||||
return *m_handles.Get(p_handleSlotKey);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* HandleContainers
|
||||
*/
|
||||
StableSlotMap<ContainerHandle> m_handles;
|
||||
|
||||
/*
|
||||
* Every Asset added to the map
|
||||
*/
|
||||
ankerl::unordered_dense::segmented_map<UUID, Entry> m_uuidToEntry;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -140,6 +266,13 @@ class AssetContainer: public AssetContainerBase
|
||||
|
||||
~AssetContainer() = default;
|
||||
|
||||
/*
|
||||
* Inserts an Asset to the AssetContainer
|
||||
*
|
||||
* \tparam ARGS Arguments to construct the asset
|
||||
* \param p_args The arguments
|
||||
* \return The key to the inserted asset.
|
||||
*/
|
||||
template<class... ARGS>
|
||||
[[nodiscard]]
|
||||
SlotMapKey Insert(ARGS&&... p_args)
|
||||
@@ -147,46 +280,69 @@ class AssetContainer: public AssetContainerBase
|
||||
SlotMapKey slotKey = m_assets.Insert(std::forward<ARGS>(p_args)...);
|
||||
ASSET* asset = m_assets.Get(slotKey);
|
||||
|
||||
if (const auto it = m_uuidToAssetSlotKey.find(asset->GetHeader().uuid); it != m_uuidToAssetSlotKey.end())
|
||||
Entry& entry = GetOrCreateEntry(asset->GetHeader().uuid);
|
||||
if (entry.m_assetSlotKey.Valid())
|
||||
{
|
||||
m_assets.Remove(slotKey);
|
||||
slotKey = it->second;
|
||||
slotKey = entry.m_assetSlotKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uuidToAssetSlotKey.emplace(asset->GetHeader().uuid, slotKey);
|
||||
AcquireHandle(asset->GetHeader().uuid).SetAsset(asset);
|
||||
entry.m_assetSlotKey = slotKey;
|
||||
FindContainerHandle(entry.m_handleSlotKey).SetAsset(asset);
|
||||
}
|
||||
|
||||
return slotKey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the Asset
|
||||
*
|
||||
* \param p_key The key to the asset
|
||||
* \return Pointer to the Asset
|
||||
*/
|
||||
[[nodiscard]]
|
||||
ASSET* Get(const SlotMapKey p_key)
|
||||
{
|
||||
return m_assets.Get(p_key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the Asset
|
||||
*
|
||||
* \param p_key The key to the asset
|
||||
* \return Pointer to the Asset
|
||||
*/
|
||||
[[nodiscard]]
|
||||
const ASSET* Get(const SlotMapKey p_key) const
|
||||
{
|
||||
return m_assets.Get(p_key);
|
||||
}
|
||||
|
||||
void Remove(const UUID& p_uuid)
|
||||
/*
|
||||
* Remove an Asset from the AssetContainer
|
||||
*
|
||||
* \param p_uuid The UUID to remove
|
||||
*/
|
||||
void Remove(const UUID& p_uuid) override
|
||||
{
|
||||
if (const auto it = m_uuidToAssetSlotKey.find(p_uuid); it != m_uuidToAssetSlotKey.end())
|
||||
if (Entry* entry = FindEntry(p_uuid); entry != nullptr && entry->m_assetSlotKey.Valid())
|
||||
{
|
||||
AcquireHandle(p_uuid).SetAsset(nullptr);
|
||||
m_assets.Remove(it->second);
|
||||
m_uuidToAssetSlotKey.erase(it->first);
|
||||
FindContainerHandle(entry->m_handleSlotKey).SetAsset(nullptr);
|
||||
m_assets.Remove(entry->m_assetSlotKey);
|
||||
entry->m_assetSlotKey = SlotMapKey {};
|
||||
}
|
||||
|
||||
AssetContainerBase::Remove(p_uuid);
|
||||
}
|
||||
|
||||
AssetContainer& operator=(const AssetContainer& p_container) = delete;
|
||||
AssetContainer& operator=(AssetContainer&& p_container) = default;
|
||||
|
||||
private:
|
||||
/*
|
||||
* The assets
|
||||
*/
|
||||
StableSlotMap<ASSET> m_assets;
|
||||
};
|
||||
} // namespace Bigfoot
|
||||
|
||||
@@ -118,7 +118,7 @@ class AssetLibrary
|
||||
{
|
||||
for (const auto& [typeID, container]: m_assetContainers)
|
||||
{
|
||||
if (container->GetAssetSlotKey(p_uuid).Valid())
|
||||
if (container->Has(p_uuid))
|
||||
{
|
||||
return container;
|
||||
}
|
||||
@@ -138,7 +138,7 @@ class AssetLibrary
|
||||
{
|
||||
for (const auto& [typeID, container]: m_assetContainers)
|
||||
{
|
||||
if (container->GetAssetSlotKey(p_uuid).Valid())
|
||||
if (container->Has(p_uuid))
|
||||
{
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ class HardReference
|
||||
{
|
||||
if (!m_handle)
|
||||
{
|
||||
m_handle = &assetContainer->AcquireHandle(m_uuid);
|
||||
m_handle = &assetContainer->AcquireContainerHandle(m_uuid);
|
||||
}
|
||||
m_handle->IncrementSoftRefCount();
|
||||
}
|
||||
@@ -234,7 +234,7 @@ class SoftReference
|
||||
{
|
||||
if (!m_handle)
|
||||
{
|
||||
m_handle = &assetContainer->AcquireHandle(m_uuid);
|
||||
m_handle = &assetContainer->AcquireContainerHandle(m_uuid);
|
||||
}
|
||||
m_handle->IncrementSoftRefCount();
|
||||
}
|
||||
|
||||
@@ -19,4 +19,91 @@ class AssetContainerFixture: public ::testing::Test
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Has_ShouldReturnTrueIfTheContainerHasTheAsset)
|
||||
{
|
||||
AssetA asset1;
|
||||
std::ignore = m_containerA.Insert(asset1);
|
||||
EXPECT_TRUE(m_containerA.Has(asset1.GetHeader().uuid));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Has_ShouldReturnFalseIfTheContainerDoesNotHaveTheAsset)
|
||||
{
|
||||
AssetA asset1;
|
||||
EXPECT_FALSE(m_containerA.Has(asset1.GetHeader().uuid));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, AcquireHandle_ShouldReturnTheAssociatedContainerHandle)
|
||||
{
|
||||
AssetA asset1;
|
||||
std::ignore = m_containerA.Insert(asset1);
|
||||
|
||||
const ContainerHandle& handle = m_containerA.AcquireContainerHandle(asset1.GetHeader().uuid);
|
||||
EXPECT_EQ(static_cast<const AssetA*>(handle.GetAsset())->GetHeader().uuid, asset1.GetHeader().uuid);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, AcquireHandle_ShouldCreateTheAssociatedContainerHandleIfItDoesNotExists)
|
||||
{
|
||||
AssetA asset1;
|
||||
|
||||
const ContainerHandle& handle = m_containerA.AcquireContainerHandle(asset1.GetHeader().uuid);
|
||||
EXPECT_EQ(handle.GetAsset(), nullptr);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Insert_ShouldReturnValidAndUniqueSlotKeyOnInsert)
|
||||
{
|
||||
AssetA asset1;
|
||||
const SlotMapKey slotKey = m_containerA.Insert(asset1);
|
||||
EXPECT_TRUE(slotKey.Valid());
|
||||
EXPECT_NE(slotKey, m_containerA.Insert());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Insert_ShouldReturnTheSameSlotKeyInCaseOfDuplicatedUUID)
|
||||
{
|
||||
AssetA asset;
|
||||
const SlotMapKey slotKey = m_containerA.Insert(asset);
|
||||
EXPECT_EQ(slotKey, m_containerA.Insert(asset));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Get_ShouldReturnTheAssetWithTheSlotKey)
|
||||
{
|
||||
AssetA asset;
|
||||
const SlotMapKey slotKey = m_containerA.Insert(asset);
|
||||
|
||||
EXPECT_EQ(m_containerA.Get(slotKey)->GetHeader().uuid, asset.GetHeader().uuid);
|
||||
EXPECT_EQ(const_cast<const AssetContainer<AssetA>&>(m_containerA).Get(slotKey)->GetHeader().uuid,
|
||||
asset.GetHeader().uuid);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Get_ShouldReturnNullptrIfSlotKeyNotInContainer)
|
||||
{
|
||||
EXPECT_EQ(m_containerA.Get(SlotMapKey {1, 0}), nullptr);
|
||||
EXPECT_EQ(const_cast<const AssetContainer<AssetA>&>(m_containerA).Get(SlotMapKey {1, 0}), nullptr);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(AssetContainerFixture, Remove_ShouldRemoveTheAsset)
|
||||
{
|
||||
AssetA asset;
|
||||
const SlotMapKey slotKey = m_containerA.Insert(asset);
|
||||
|
||||
m_containerA.Remove(asset.GetHeader().uuid);
|
||||
|
||||
EXPECT_EQ(m_containerA.Get(slotKey), nullptr);
|
||||
EXPECT_FALSE(m_containerA.Has(asset.GetHeader().uuid));
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
|
||||
Reference in New Issue
Block a user