format
Bigfoot / Sonarqube (push) Skipped
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Failing after 10m27s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Successful in 6m3s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Canceled after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Canceled after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Canceled after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Canceled after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Canceled after 0s
Bigfoot / Clang Format Checks (push) Canceled after 0s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Canceled after 2m34s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Successful in 5m30s

This commit is contained in:
2026-08-17 18:08:27 +02:00
parent 96c4353a8a
commit 6bc25a776e
3 changed files with 57 additions and 61 deletions
@@ -121,6 +121,7 @@ class AssetContainerBase
{ {
using SlotMap = StableSlotMap<ContainerHandle>; using SlotMap = StableSlotMap<ContainerHandle>;
using SlotMapKey = SlotMap::SlotMapKey; using SlotMapKey = SlotMap::SlotMapKey;
public: public:
virtual ~AssetContainerBase() = default; virtual ~AssetContainerBase() = default;
@@ -262,6 +263,7 @@ class AssetContainer: public AssetContainerBase
{ {
using SlotMap = StableSlotMap<ASSET>; using SlotMap = StableSlotMap<ASSET>;
using SlotMapKey = SlotMap::SlotMapKey; using SlotMapKey = SlotMap::SlotMapKey;
public: public:
AssetContainer() = default; AssetContainer() = default;
@@ -10,18 +10,9 @@
#include <EASTL/array.h> #include <EASTL/array.h>
#include <EASTL/bitset.h> #include <EASTL/bitset.h>
#include <EASTL/iterator.h> #include <EASTL/numeric.h>
#include <EASTL/unique_ptr.h> #include <EASTL/unique_ptr.h>
#include <EASTL/vector.h> #include <EASTL/vector.h>
#include <EASTL/numeric.h>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
namespace Bigfoot namespace Bigfoot
{ {
@@ -150,7 +141,8 @@ class DenseSlotMap
const std::size_t indexToRecyclingKey = m_freeListHead; const std::size_t indexToRecyclingKey = m_freeListHead;
m_freeListHead = m_keys[indexToRecyclingKey].GetIndex(); m_freeListHead = m_keys[indexToRecyclingKey].GetIndex();
m_keys[indexToRecyclingKey] = SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(), static_cast<SlotMapKey::IndexType>(indexToInsertedData)}; m_keys[indexToRecyclingKey] = SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(),
static_cast<SlotMapKey::IndexType>(indexToInsertedData)};
m_dataToKey.emplace_back(indexToRecyclingKey); m_dataToKey.emplace_back(indexToRecyclingKey);
return SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(), return SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(),
@@ -305,7 +297,8 @@ class DenseSlotMap
void RecycleKey(const SlotMapKey p_key) void RecycleKey(const SlotMapKey p_key)
{ {
const typename SlotMapKey::VersionType nextVersion = static_cast<SlotMapKey::VersionType>(p_key.GetVersion() + 1); const typename SlotMapKey::VersionType nextVersion = static_cast<SlotMapKey::VersionType>(p_key.GetVersion() +
1);
if (nextVersion == SlotMapKey::INVALID_VERSION) if (nextVersion == SlotMapKey::INVALID_VERSION)
{ {
@@ -345,7 +338,6 @@ class StableSlotMap
alignas(T) std::byte m_bytes[sizeof(T)]; alignas(T) std::byte m_bytes[sizeof(T)];
}; };
struct Page struct Page
{ {
Page() = default; Page() = default;
@@ -395,8 +387,9 @@ class StableSlotMap
{ {
private: private:
using PagesVector = eastl::vector<eastl::unique_ptr<Page>>; using PagesVector = eastl::vector<eastl::unique_ptr<Page>>;
using PageIterator = using PageIterator = std::conditional_t<std::is_const_v<VALUE_TYPE>,
std::conditional_t<std::is_const_v<VALUE_TYPE>, typename PagesVector::const_iterator, typename PagesVector::iterator>; typename PagesVector::const_iterator,
typename PagesVector::iterator>;
using MapType = std::conditional_t<std::is_const_v<VALUE_TYPE>, const StableSlotMap, StableSlotMap>; using MapType = std::conditional_t<std::is_const_v<VALUE_TYPE>, const StableSlotMap, StableSlotMap>;
using PageType = std::conditional_t<std::is_const_v<VALUE_TYPE>, const Page, Page>; using PageType = std::conditional_t<std::is_const_v<VALUE_TYPE>, const Page, Page>;
@@ -585,12 +578,12 @@ class StableSlotMap
std::size_t Size() const std::size_t Size() const
{ {
return eastl::accumulate(m_pages.begin(), return eastl::accumulate(m_pages.begin(),
m_pages.end(), m_pages.end(),
0, 0,
[](const std::size_t p_value, const eastl::unique_ptr<Page>& p_page) [](const std::size_t p_value, const eastl::unique_ptr<Page>& p_page)
{ {
return p_value + p_page->Size(); return p_value + p_page->Size();
}); });
} }
[[nodiscard]] [[nodiscard]]
+41 -40
View File
@@ -14,7 +14,7 @@ namespace Bigfoot
class SlotMapKeyFixture: public ::testing::Test class SlotMapKeyFixture: public ::testing::Test
{ {
protected: protected:
using SlotMapKey = SlotMapKey<>; using SlotMapKey = SlotMapKey<>;
}; };
/****************************************************************************************/ /****************************************************************************************/
@@ -155,7 +155,8 @@ class SlotMapNameGenerator
} }
}; };
using SlotMapTypes = ::testing::Types<DenseSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>, StableSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>>; using SlotMapTypes = ::testing::Types<DenseSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>,
StableSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>>;
TYPED_TEST_SUITE(SlotMapFixture, SlotMapTypes, SlotMapNameGenerator); TYPED_TEST_SUITE(SlotMapFixture, SlotMapTypes, SlotMapNameGenerator);
/****************************************************************************************/ /****************************************************************************************/
@@ -1114,51 +1115,51 @@ TYPED_TEST(SlotMapFixture, ConstReverseIterator)
/****************************************************************************************/ /****************************************************************************************/
class StableSlotMapFixture: public ::testing::Test class StableSlotMapFixture: public ::testing::Test
{ {
protected: protected:
StableSlotMap<std::uint32_t> m_slotMap; StableSlotMap<std::uint32_t> m_slotMap;
using SlotMapKey = StableSlotMap<std::uint32_t>::SlotMapKey; using SlotMapKey = StableSlotMap<std::uint32_t>::SlotMapKey;
}; };
/****************************************************************************************/ /****************************************************************************************/
TEST_F(StableSlotMapFixture, PointersAreStable) TEST_F(StableSlotMapFixture, PointersAreStable)
{ {
const SlotMapKey key = m_slotMap.Insert(42); const SlotMapKey key = m_slotMap.Insert(42);
const std::uint32_t* const pointer = m_slotMap.Get(key); const std::uint32_t* const pointer = m_slotMap.Get(key);
// Inserting enough elements to span multiple pages (PAGE_SIZE is 64) must not move already // Inserting enough elements to span multiple pages (PAGE_SIZE is 64) must not move already
// -inserted data: unlike DenseSlotMap's contiguous eastl::vector, growth only appends new // -inserted data: unlike DenseSlotMap's contiguous eastl::vector, growth only appends new
// Page objects (each individually heap-allocated), it never reallocates existing ones. // Page objects (each individually heap-allocated), it never reallocates existing ones.
constexpr std::uint32_t elementCount = 200; constexpr std::uint32_t elementCount = 200;
eastl::array<SlotMapKey, elementCount> keys; eastl::array<SlotMapKey, elementCount> keys;
for (std::uint32_t value = 0; value < elementCount; ++value) for (std::uint32_t value = 0; value < elementCount; ++value)
{ {
keys[value] = m_slotMap.Insert(value); keys[value] = m_slotMap.Insert(value);
} }
EXPECT_EQ(m_slotMap.Get(key), pointer); EXPECT_EQ(m_slotMap.Get(key), pointer);
EXPECT_EQ(*pointer, 42); EXPECT_EQ(*pointer, 42);
// Removing unrelated elements, including ones sharing the same page as key, must not move it // Removing unrelated elements, including ones sharing the same page as key, must not move it
// either: Remove() only destroys that slot in place, it never compacts the page's array. // either: Remove() only destroys that slot in place, it never compacts the page's array.
for (std::uint32_t value = 0; value < elementCount; value += 2) for (std::uint32_t value = 0; value < elementCount; value += 2)
{ {
m_slotMap.Remove(keys[value]); m_slotMap.Remove(keys[value]);
} }
EXPECT_EQ(m_slotMap.Get(key), pointer); EXPECT_EQ(m_slotMap.Get(key), pointer);
EXPECT_EQ(*pointer, 42); EXPECT_EQ(*pointer, 42);
// Re-inserting into the freed slots must not move it either // Re-inserting into the freed slots must not move it either
for (std::uint32_t value = 0; value < elementCount / 2; ++value) for (std::uint32_t value = 0; value < elementCount / 2; ++value)
{ {
std::ignore = m_slotMap.Insert(value); std::ignore = m_slotMap.Insert(value);
} }
EXPECT_EQ(m_slotMap.Get(key), pointer); EXPECT_EQ(m_slotMap.Get(key), pointer);
EXPECT_EQ(*pointer, 42); EXPECT_EQ(*pointer, 42);
} }
} // namespace Bigfoot } // namespace Bigfoot