SlotMap benchmark
Some checks failed
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Successful in 5m20s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Successful in 5m17s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Successful in 5m55s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Has been cancelled
Bigfoot / Clang Format Checks (push) Has been cancelled
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Has been cancelled
Some checks failed
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Successful in 5m20s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Successful in 5m17s
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Successful in 5m55s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: OFF) (push) Has been cancelled
Bigfoot / Build & Test Release with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Has been cancelled
Bigfoot / Clang Format Checks (push) Has been cancelled
Bigfoot / Build & Test Debug with ./ConanProfiles/clang_asan (Unity Build: ON) (push) Has been cancelled
This commit is contained in:
1
Bigfoot/Benchmarks/CMakeLists.txt
Normal file
1
Bigfoot/Benchmarks/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
5
Bigfoot/Benchmarks/Utils/CMakeLists.txt
Normal file
5
Bigfoot/Benchmarks/Utils/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
project(${PackageName}Benchmarks)
|
||||||
|
|
||||||
|
bigfoot_create_package_benchmarks(
|
||||||
|
"")
|
||||||
250
Bigfoot/Benchmarks/Utils/Container/SlotMap.cpp
Normal file
250
Bigfoot/Benchmarks/Utils/Container/SlotMap.cpp
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
#include <Utils/Containers/SlotMap.hpp>
|
||||||
|
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <random>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
struct MyComplexStruct
|
||||||
|
{
|
||||||
|
std::uint32_t m_actualValueForBench = 0; // field summed by the Iterate benchmark
|
||||||
|
|
||||||
|
float m_position[3] = {0.0f, 0.0f, 0.0f};
|
||||||
|
float m_rotation[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
float m_scale[3] = {1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
std::uint64_t m_entityId = 0;
|
||||||
|
std::uint32_t m_parentSlot = 0;
|
||||||
|
std::uint32_t m_flags = 0;
|
||||||
|
|
||||||
|
MyComplexStruct() = default;
|
||||||
|
|
||||||
|
explicit MyComplexStruct(const std::uint32_t p_value):
|
||||||
|
m_actualValueForBench(p_value),
|
||||||
|
m_entityId(p_value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(MyComplexStruct) == 64, "Payload should be exactly one cache line.");
|
||||||
|
static_assert(std::is_trivially_copyable_v<MyComplexStruct>,
|
||||||
|
"Container moves should be a plain memcpy, not a heap-touching move.");
|
||||||
|
|
||||||
|
class SlotMapAdaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Key = SlotMap<MyComplexStruct>::SlotKey;
|
||||||
|
|
||||||
|
Key Add(MyComplexStruct&& p_value)
|
||||||
|
{
|
||||||
|
return m_container.Insert(std::move(p_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
const MyComplexStruct* Find(const Key p_key) const
|
||||||
|
{
|
||||||
|
return m_container.Get(p_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Remove(const Key p_key)
|
||||||
|
{
|
||||||
|
m_container.Remove(p_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
m_container.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FUNC>
|
||||||
|
void ForEachValue(FUNC&& p_func) const
|
||||||
|
{
|
||||||
|
for (const MyComplexStruct& value: m_container)
|
||||||
|
{
|
||||||
|
p_func(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SlotMap<MyComplexStruct> m_container;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class MAP>
|
||||||
|
class HashMapHarnessAdaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Key = typename MAP::key_type;
|
||||||
|
|
||||||
|
Key Add(MyComplexStruct&& p_value)
|
||||||
|
{
|
||||||
|
const Key key = m_nextKey++;
|
||||||
|
m_container.emplace(key, std::move(p_value));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MyComplexStruct* Find(const Key p_key) const
|
||||||
|
{
|
||||||
|
const auto it = m_container.find(p_key);
|
||||||
|
return it != m_container.end() ? &it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Remove(const Key p_key)
|
||||||
|
{
|
||||||
|
m_container.erase(p_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
m_container.clear();
|
||||||
|
m_nextKey = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FUNC>
|
||||||
|
void ForEachValue(FUNC&& p_func) const
|
||||||
|
{
|
||||||
|
for (const auto& keyValue: m_container)
|
||||||
|
{
|
||||||
|
p_func(keyValue.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MAP m_container;
|
||||||
|
Key m_nextKey = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ADAPTOR>
|
||||||
|
void Insert(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
ADAPTOR adaptor;
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
benchmark::DoNotOptimize(adaptor.Add(MyComplexStruct {i}));
|
||||||
|
}
|
||||||
|
benchmark::DoNotOptimize(adaptor);
|
||||||
|
benchmark::ClobberMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ADAPTOR>
|
||||||
|
void Remove(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
ADAPTOR adaptor;
|
||||||
|
std::vector<typename ADAPTOR::Key> keys;
|
||||||
|
keys.reserve(count);
|
||||||
|
std::mt19937 rng(0x5EEDU);
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
state.PauseTiming();
|
||||||
|
adaptor.Clear();
|
||||||
|
keys.clear();
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
keys.push_back(adaptor.Add(MyComplexStruct {i}));
|
||||||
|
}
|
||||||
|
std::shuffle(keys.begin(), keys.end(), rng);
|
||||||
|
state.ResumeTiming();
|
||||||
|
|
||||||
|
for (const typename ADAPTOR::Key key: keys)
|
||||||
|
{
|
||||||
|
adaptor.Remove(key);
|
||||||
|
}
|
||||||
|
benchmark::DoNotOptimize(adaptor);
|
||||||
|
benchmark::ClobberMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ADAPTOR>
|
||||||
|
void Get(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
ADAPTOR adaptor;
|
||||||
|
std::vector<typename ADAPTOR::Key> keys;
|
||||||
|
keys.reserve(count);
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
keys.push_back(adaptor.Add(MyComplexStruct {i}));
|
||||||
|
}
|
||||||
|
std::mt19937 rng(0x5EEDU);
|
||||||
|
std::shuffle(keys.begin(), keys.end(), rng);
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
std::uint64_t sum = 0;
|
||||||
|
for (const typename ADAPTOR::Key key: keys)
|
||||||
|
{
|
||||||
|
if (const MyComplexStruct* const value = adaptor.Find(key))
|
||||||
|
{
|
||||||
|
sum += value->m_actualValueForBench;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
benchmark::DoNotOptimize(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ADAPTOR>
|
||||||
|
void Iterate(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
ADAPTOR adaptor;
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
adaptor.Add(MyComplexStruct {i});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
std::uint64_t sum = 0;
|
||||||
|
adaptor.ForEachValue(
|
||||||
|
[&sum](const MyComplexStruct& value)
|
||||||
|
{
|
||||||
|
sum += value.m_actualValueForBench;
|
||||||
|
});
|
||||||
|
benchmark::DoNotOptimize(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register all four benchmarks for one container adapter under a readable name.
|
||||||
|
#define BIGFOOT_REGISTER_BENCHMARKS(ADAPTOR, NAME) \
|
||||||
|
BENCHMARK_TEMPLATE(Insert, ADAPTOR)->Name(NAME "/Insert")->Range(8, 8 << 16); \
|
||||||
|
BENCHMARK_TEMPLATE(Remove, ADAPTOR)->Name(NAME "/Remove")->Range(8, 8 << 16); \
|
||||||
|
BENCHMARK_TEMPLATE(Get, ADAPTOR)->Name(NAME "/Get")->Range(8, 8 << 16); \
|
||||||
|
BENCHMARK_TEMPLATE(Iterate, ADAPTOR)->Name(NAME "/Iterate")->Range(8, 8 << 16)
|
||||||
|
|
||||||
|
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(UnorderedDenseMapHarness, "ankerl::unordered_dense::map");
|
||||||
|
BIGFOOT_REGISTER_BENCHMARKS(UnorderedDenseSegementedMapHarness, "ankerl::unordered_dense::segmented_map");
|
||||||
|
BIGFOOT_REGISTER_BENCHMARKS(UnorderedMapHarness, "std::unordered_map");
|
||||||
|
BIGFOOT_REGISTER_BENCHMARKS(MapHarness, "std::map");
|
||||||
|
|
||||||
|
#undef BIGFOOT_REGISTER_BENCHMARKS
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -19,7 +19,7 @@ namespace Bigfoot
|
|||||||
template<class TYPE,
|
template<class TYPE,
|
||||||
class VERSION_TYPE = std::uint32_t,
|
class VERSION_TYPE = std::uint32_t,
|
||||||
class INDEX_TYPE = std::uint32_t,
|
class INDEX_TYPE = std::uint32_t,
|
||||||
std::enable_if_t<std::is_integral_v<VERSION_TYPE> && std::is_integral_v<INDEX_TYPE>, bool> = true>
|
std::enable_if_t<std::is_unsigned_v<VERSION_TYPE> && std::is_unsigned_v<INDEX_TYPE>, bool> = true>
|
||||||
class SlotMap
|
class SlotMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -43,42 +43,42 @@ class SlotMap
|
|||||||
|
|
||||||
static constexpr IndexType MAX_INDEX = std::numeric_limits<IndexType>::max();
|
static constexpr IndexType MAX_INDEX = std::numeric_limits<IndexType>::max();
|
||||||
|
|
||||||
SlotKey(const VersionType p_version, const IndexType p_index):
|
constexpr SlotKey(const VersionType p_version, const IndexType p_index):
|
||||||
m_key((static_cast<std::uint64_t>(p_version) << INDEX_BIT_COUNT) |
|
m_key((static_cast<std::uint64_t>(p_version) << INDEX_BIT_COUNT) |
|
||||||
(static_cast<std::uint64_t>(p_index) & INDEX_MASK))
|
(static_cast<std::uint64_t>(p_index) & INDEX_MASK))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SlotKey():
|
constexpr SlotKey():
|
||||||
SlotKey(INVALID_VERSION, 0)
|
SlotKey(INVALID_VERSION, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SlotKey(const SlotKey& p_slotKey) = default;
|
constexpr SlotKey(const SlotKey& p_slotKey) = default;
|
||||||
SlotKey(SlotKey&& p_slotKey) = default;
|
constexpr SlotKey(SlotKey&& p_slotKey) = default;
|
||||||
|
|
||||||
~SlotKey() = default;
|
constexpr ~SlotKey() = default;
|
||||||
|
|
||||||
bool Valid() const
|
constexpr bool Valid() const
|
||||||
{
|
{
|
||||||
return Version() != INVALID_VERSION;
|
return Version() != INVALID_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionType Version() const
|
constexpr VersionType Version() const
|
||||||
{
|
{
|
||||||
return static_cast<VersionType>(m_key >> INDEX_BIT_COUNT);
|
return static_cast<VersionType>(m_key >> INDEX_BIT_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexType Index() const
|
constexpr IndexType Index() const
|
||||||
{
|
{
|
||||||
return static_cast<IndexType>(m_key & INDEX_MASK);
|
return static_cast<IndexType>(m_key & INDEX_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
SlotKey& operator=(const SlotKey& p_slotKey) = default;
|
constexpr SlotKey& operator=(const SlotKey& p_slotKey) = default;
|
||||||
SlotKey& operator=(SlotKey&& p_slotKey) = default;
|
constexpr SlotKey& operator=(SlotKey&& p_slotKey) = default;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool operator==(const SlotKey& p_other) const = default;
|
constexpr bool operator==(const SlotKey& p_other) const = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::uint64_t m_key;
|
std::uint64_t m_key;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
||||||
@@ -10,208 +10,258 @@
|
|||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
class SlotKeyFixture: public ::testing::Test
|
template<class VERSION_TYPE, class INDEX_TYPE>
|
||||||
|
struct SlotMapConfig
|
||||||
{
|
{
|
||||||
protected:
|
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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotKeyFixture, DefaultSlotKeyIsInvalid)
|
template<class CONFIG>
|
||||||
|
class SlotKeyFixture: public ::testing::Test
|
||||||
{
|
{
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::IndexType index = 0;
|
protected:
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::VersionType version = 0;
|
using SlotMapVersion = typename CONFIG::Version;
|
||||||
|
using SlotMapIndex = typename CONFIG::Index;
|
||||||
|
using SlotMapType = SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>;
|
||||||
|
using SlotKey = typename SlotMapType::SlotKey;
|
||||||
|
};
|
||||||
|
|
||||||
SlotMap<std::uint32_t>::SlotKey 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_FALSE(slotKey.Valid());
|
||||||
EXPECT_EQ(slotKey.Version(), index);
|
|
||||||
EXPECT_EQ(slotKey.Index(), version);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(SlotKeyFixture, Valid_ShouldReturnTrueIfTheSlotKeyIsValid)
|
|
||||||
{
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::IndexType index = 0;
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::VersionType version = 1;
|
|
||||||
|
|
||||||
SlotMap<std::uint32_t>::SlotKey slotKey {version, index};
|
|
||||||
EXPECT_TRUE(slotKey.Valid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(SlotKeyFixture, Valid_ShouldReturnFalseIfTheSlotKeyIsValid)
|
|
||||||
{
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::IndexType index = 0;
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::VersionType version = 0;
|
|
||||||
|
|
||||||
SlotMap<std::uint32_t>::SlotKey slotKey {version, index};
|
|
||||||
EXPECT_FALSE(slotKey.Valid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(SlotKeyFixture, Version_ShouldReturnTheVersion)
|
|
||||||
{
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::IndexType index = 0;
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::VersionType version = 42;
|
|
||||||
|
|
||||||
SlotMap<std::uint32_t>::SlotKey slotKey {version, index};
|
|
||||||
EXPECT_EQ(slotKey.Version(), version);
|
EXPECT_EQ(slotKey.Version(), version);
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(SlotKeyFixture, Index_ShouldReturnTheIndex)
|
|
||||||
{
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::IndexType index = 42;
|
|
||||||
constexpr SlotMap<std::uint32_t>::SlotKey::VersionType version = 0;
|
|
||||||
|
|
||||||
SlotMap<std::uint32_t>::SlotKey slotKey {version, index};
|
|
||||||
EXPECT_EQ(slotKey.Index(), index);
|
EXPECT_EQ(slotKey.Index(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
class SlotMapFixture: public ::testing::Test
|
TYPED_TEST(SlotKeyFixture, Valid_ShouldReturnTrueIfTheSlotKeyIsValid)
|
||||||
{
|
{
|
||||||
protected:
|
constexpr typename TestFixture::SlotMapIndex index = 0;
|
||||||
using SlotMapVersion = std::uint8_t;
|
constexpr typename TestFixture::SlotMapVersion version = 1;
|
||||||
using SlotMapIndex = std::uint32_t;
|
|
||||||
|
|
||||||
SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex> m_slotMap;
|
constexpr typename TestFixture::SlotKey slotKey {version, index};
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Insert_ShouldReturnAValidSlotKey)
|
|
||||||
{
|
|
||||||
const auto slotKey = m_slotMap.Insert(42);
|
|
||||||
EXPECT_TRUE(slotKey.Valid());
|
EXPECT_TRUE(slotKey.Valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Insert_ShouldRecycleASlotKeyAfterARemove)
|
TYPED_TEST(SlotKeyFixture, Valid_ShouldReturnFalseIfTheSlotKeyIsValid)
|
||||||
{
|
{
|
||||||
const auto slotKey = m_slotMap.Insert(42);
|
constexpr typename TestFixture::SlotMapIndex index = 0;
|
||||||
m_slotMap.Remove(slotKey);
|
constexpr typename TestFixture::SlotMapVersion version = 0;
|
||||||
|
|
||||||
const auto secondSlotKey = m_slotMap.Insert(69);
|
constexpr typename TestFixture::SlotKey slotKey {version, index};
|
||||||
|
EXPECT_FALSE(slotKey.Valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TYPED_TEST(SlotKeyFixture, Version_ShouldReturnTheVersion)
|
||||||
|
{
|
||||||
|
constexpr typename TestFixture::SlotMapIndex index = 0;
|
||||||
|
constexpr typename TestFixture::SlotMapVersion version = 42;
|
||||||
|
|
||||||
|
constexpr typename TestFixture::SlotKey slotKey {version, index};
|
||||||
|
EXPECT_EQ(slotKey.Version(), version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TYPED_TEST(SlotKeyFixture, Index_ShouldReturnTheIndex)
|
||||||
|
{
|
||||||
|
constexpr typename TestFixture::SlotMapIndex index = 42;
|
||||||
|
constexpr typename TestFixture::SlotMapVersion version = 0;
|
||||||
|
|
||||||
|
constexpr typename TestFixture::SlotKey slotKey {version, index};
|
||||||
|
EXPECT_EQ(slotKey.Index(), 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.Version(), slotKey.Version());
|
EXPECT_NE(secondSlotKey.Version(), slotKey.Version());
|
||||||
EXPECT_EQ(secondSlotKey.Index(), slotKey.Index());
|
EXPECT_EQ(secondSlotKey.Index(), slotKey.Index());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Has_ShouldReturnTrueIfTheSlotMapHasTheKey)
|
TYPED_TEST(SlotMapFixture, Has_ShouldReturnTrueIfTheSlotMapHasTheKey)
|
||||||
{
|
{
|
||||||
const auto slotKey = m_slotMap.Insert(42);
|
const auto slotKey = this->m_slotMap.Insert(42);
|
||||||
EXPECT_TRUE(m_slotMap.Has(slotKey));
|
EXPECT_TRUE(this->m_slotMap.Has(slotKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Has_ShouldReturnFalseIfTheSlotMapDoesNotHaveTheKey)
|
TYPED_TEST(SlotMapFixture, Has_ShouldReturnFalseIfTheSlotMapDoesNotHaveTheKey)
|
||||||
{
|
{
|
||||||
const auto slotKey = m_slotMap.Insert(42);
|
const auto slotKey = this->m_slotMap.Insert(42);
|
||||||
m_slotMap.Remove(slotKey);
|
this->m_slotMap.Remove(slotKey);
|
||||||
EXPECT_FALSE(m_slotMap.Has(slotKey));
|
EXPECT_FALSE(this->m_slotMap.Has(slotKey));
|
||||||
EXPECT_FALSE(m_slotMap.Has((SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>::SlotKey {1, 22})));
|
EXPECT_FALSE(this->m_slotMap.Has(typename TestFixture::SlotKey {1, 22}));
|
||||||
EXPECT_FALSE(m_slotMap.Has((SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>::SlotKey {})));
|
EXPECT_FALSE(this->m_slotMap.Has(typename TestFixture::SlotKey {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Remove_ShouldRemoveTheSlotKey)
|
TYPED_TEST(SlotMapFixture, Remove_ShouldRemoveTheSlotKey)
|
||||||
{
|
{
|
||||||
const auto slotKey = m_slotMap.Insert(42);
|
const auto slotKey = this->m_slotMap.Insert(42);
|
||||||
m_slotMap.Remove(slotKey);
|
this->m_slotMap.Remove(slotKey);
|
||||||
EXPECT_FALSE(m_slotMap.Has(slotKey));
|
EXPECT_FALSE(this->m_slotMap.Has(slotKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Remove_ShouldNotRecycleASlotWhenVersionWasExhausted)
|
TYPED_TEST(SlotMapFixture, Remove_ShouldNotRecycleASlotWhenVersionWasExhausted)
|
||||||
{
|
{
|
||||||
auto key = m_slotMap.Insert(1);
|
if constexpr (std::is_same_v<typename TestFixture::SlotMapVersion, std::uint32_t>)
|
||||||
|
|
||||||
for (SlotMapVersion i = 1; i < std::numeric_limits<SlotMapVersion>::max(); ++i)
|
|
||||||
{
|
{
|
||||||
m_slotMap.Remove(key);
|
GTEST_SKIP() << "Skipped for 32-bit version: exhausting all versions is too slow.";
|
||||||
const auto newKey = m_slotMap.Insert(1);
|
|
||||||
EXPECT_EQ(newKey.Index(), key.Index());
|
|
||||||
key = newKey;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto key = this->m_slotMap.Insert(1);
|
||||||
|
|
||||||
// Slot is at MAX_VERSION — one more remove should overflow and permanently deactivate it
|
for (typename TestFixture::SlotMapVersion i = 1;
|
||||||
EXPECT_EQ(key.Version(), std::numeric_limits<SlotMapVersion>::max());
|
i < std::numeric_limits<typename TestFixture::SlotMapVersion>::max();
|
||||||
m_slotMap.Remove(key);
|
++i)
|
||||||
|
{
|
||||||
|
this->m_slotMap.Remove(key);
|
||||||
|
const auto newKey = this->m_slotMap.Insert(1);
|
||||||
|
EXPECT_EQ(newKey.Index(), key.Index());
|
||||||
|
key = newKey;
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT_FALSE(m_slotMap.Has(key));
|
// Slot is at MAX_VERSION — one more remove should overflow and permanently deactivate it
|
||||||
|
EXPECT_EQ(key.Version(), std::numeric_limits<typename TestFixture::SlotMapVersion>::max());
|
||||||
|
this->m_slotMap.Remove(key);
|
||||||
|
|
||||||
// Dead slot must not be recycled; a new insert must allocate a fresh slot index
|
EXPECT_FALSE(this->m_slotMap.Has(key));
|
||||||
const auto newKey = m_slotMap.Insert(2);
|
|
||||||
EXPECT_NE(newKey.Index(), key.Index());
|
|
||||||
|
|
||||||
// Ensure an invalid key does not return an exhausted slot
|
// Dead slot must not be recycled; a new insert must allocate a fresh slot index
|
||||||
EXPECT_EQ(m_slotMap.Get(SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>::SlotKey {}), nullptr);
|
const auto newKey = this->m_slotMap.Insert(2);
|
||||||
|
EXPECT_NE(newKey.Index(), key.Index());
|
||||||
|
|
||||||
|
// Ensure an invalid key does not return an exhausted slot
|
||||||
|
EXPECT_EQ(this->m_slotMap.Get(typename TestFixture::SlotKey {}), nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Remove_ShouldNotDoAnythingInCaseOfDoubleRemove)
|
TYPED_TEST(SlotMapFixture, Remove_ShouldNotDoAnythingInCaseOfDoubleRemove)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey1);
|
this->m_slotMap.Remove(slotKey1);
|
||||||
m_slotMap.Remove(slotKey1);
|
this->m_slotMap.Remove(slotKey1);
|
||||||
|
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey2), 69);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey2), 69);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Remove_ShouldNotDoAnythingInCaseStaleKey)
|
TYPED_TEST(SlotMapFixture, Remove_ShouldNotDoAnythingInCaseStaleKey)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
|
|
||||||
m_slotMap.Remove(SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>::SlotKey {2, 0});
|
this->m_slotMap.Remove(typename TestFixture::SlotKey {2, 0});
|
||||||
|
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey1), 42);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Get_ShouldReturnNullptrForInvalidSlotKeys)
|
TYPED_TEST(SlotMapFixture, Get_ShouldReturnNullptrForInvalidSlotKeys)
|
||||||
{
|
{
|
||||||
const auto slotKey = m_slotMap.Insert(42);
|
const auto slotKey = this->m_slotMap.Insert(42);
|
||||||
m_slotMap.Remove(slotKey);
|
this->m_slotMap.Remove(slotKey);
|
||||||
|
|
||||||
const auto validate = [&](auto& p_slotMap)
|
const auto validate = [&](auto& p_slotMap)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(p_slotMap.Get(slotKey), nullptr);
|
EXPECT_EQ(p_slotMap.Get(slotKey), nullptr);
|
||||||
EXPECT_EQ(p_slotMap.Get(SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>::SlotKey {1, 3}), nullptr);
|
EXPECT_EQ(p_slotMap.Get(typename TestFixture::SlotKey {1, 3}), nullptr);
|
||||||
EXPECT_EQ(p_slotMap.Get(SlotMap<std::uint32_t, SlotMapVersion, SlotMapIndex>::SlotKey {}), nullptr);
|
EXPECT_EQ(p_slotMap.Get(typename TestFixture::SlotKey {}), nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
validate(m_slotMap);
|
validate(this->m_slotMap);
|
||||||
const auto& constSlotMap = m_slotMap;
|
const auto& constSlotMap = this->m_slotMap;
|
||||||
validate(constSlotMap);
|
validate(constSlotMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Get_ShouldReturnTheValueForValidSlotKeys)
|
TYPED_TEST(SlotMapFixture, Get_ShouldReturnTheValueForValidSlotKeys)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
const auto slotKey3 = m_slotMap.Insert(28);
|
const auto slotKey3 = this->m_slotMap.Insert(28);
|
||||||
const auto slotKey4 = m_slotMap.Insert(0);
|
const auto slotKey4 = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey2);
|
this->m_slotMap.Remove(slotKey2);
|
||||||
|
|
||||||
const auto validate = [&](auto& p_slotMap)
|
const auto validate = [&](auto& p_slotMap)
|
||||||
{
|
{
|
||||||
@@ -220,150 +270,150 @@ TEST_F(SlotMapFixture, Get_ShouldReturnTheValueForValidSlotKeys)
|
|||||||
EXPECT_EQ(*p_slotMap.Get(slotKey4), 0);
|
EXPECT_EQ(*p_slotMap.Get(slotKey4), 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
validate(m_slotMap);
|
validate(this->m_slotMap);
|
||||||
const auto& constSlotMap = m_slotMap;
|
const auto& constSlotMap = this->m_slotMap;
|
||||||
validate(constSlotMap);
|
validate(constSlotMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Reset_ResetsTheSlotMapAndMakesCollisionWithOldSlotKeys)
|
TYPED_TEST(SlotMapFixture, Reset_ResetsTheSlotMapAndMakesCollisionWithOldSlotKeys)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Reset();
|
this->m_slotMap.Reset();
|
||||||
|
|
||||||
const auto slotKey5 = m_slotMap.Insert(128);
|
const auto slotKey5 = this->m_slotMap.Insert(128);
|
||||||
|
|
||||||
EXPECT_EQ(slotKey1, slotKey5);
|
EXPECT_EQ(slotKey1, slotKey5);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey5), 128);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey5), 128);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey1), 128);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Clear_ResetsTheSlotMapAndButGuaranteesNotCollisionWithOldSlotKeys)
|
TYPED_TEST(SlotMapFixture, Clear_ResetsTheSlotMapAndButGuaranteesNotCollisionWithOldSlotKeys)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Clear();
|
this->m_slotMap.Clear();
|
||||||
|
|
||||||
const auto slotKey5 = m_slotMap.Insert(128);
|
const auto slotKey5 = this->m_slotMap.Insert(128);
|
||||||
|
|
||||||
EXPECT_NE(slotKey1, slotKey5);
|
EXPECT_NE(slotKey1, slotKey5);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey5), 128);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey5), 128);
|
||||||
EXPECT_EQ(m_slotMap.Get(slotKey1), nullptr);
|
EXPECT_EQ(this->m_slotMap.Get(slotKey1), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Size_ReturnTheSizeOfTheSlotMap)
|
TYPED_TEST(SlotMapFixture, Size_ReturnTheSizeOfTheSlotMap)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(m_slotMap.Size(), 0);
|
EXPECT_EQ(this->m_slotMap.Size(), 0);
|
||||||
|
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
EXPECT_EQ(m_slotMap.Size(), 4);
|
EXPECT_EQ(this->m_slotMap.Size(), 4);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey2);
|
this->m_slotMap.Remove(slotKey2);
|
||||||
|
|
||||||
EXPECT_EQ(m_slotMap.Size(), 3);
|
EXPECT_EQ(this->m_slotMap.Size(), 3);
|
||||||
|
|
||||||
m_slotMap.Clear();
|
this->m_slotMap.Clear();
|
||||||
|
|
||||||
EXPECT_EQ(m_slotMap.Size(), 0);
|
EXPECT_EQ(this->m_slotMap.Size(), 0);
|
||||||
|
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
EXPECT_EQ(m_slotMap.Size(), 4);
|
EXPECT_EQ(this->m_slotMap.Size(), 4);
|
||||||
|
|
||||||
m_slotMap.Reset();
|
this->m_slotMap.Reset();
|
||||||
|
|
||||||
EXPECT_EQ(m_slotMap.Size(), 0);
|
EXPECT_EQ(this->m_slotMap.Size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Empty_ShouldReturnTrueIfTheSlotMapIsEmpty)
|
TYPED_TEST(SlotMapFixture, Empty_ShouldReturnTrueIfTheSlotMapIsEmpty)
|
||||||
{
|
{
|
||||||
EXPECT_TRUE(m_slotMap.Empty());
|
EXPECT_TRUE(this->m_slotMap.Empty());
|
||||||
|
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Clear();
|
this->m_slotMap.Clear();
|
||||||
|
|
||||||
EXPECT_TRUE(m_slotMap.Empty());
|
EXPECT_TRUE(this->m_slotMap.Empty());
|
||||||
|
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Reset();
|
this->m_slotMap.Reset();
|
||||||
|
|
||||||
EXPECT_TRUE(m_slotMap.Empty());
|
EXPECT_TRUE(this->m_slotMap.Empty());
|
||||||
|
|
||||||
const auto slotKey9 = m_slotMap.Insert(42);
|
const auto slotKey9 = this->m_slotMap.Insert(42);
|
||||||
m_slotMap.Remove(slotKey9);
|
this->m_slotMap.Remove(slotKey9);
|
||||||
|
|
||||||
EXPECT_TRUE(m_slotMap.Empty());
|
EXPECT_TRUE(this->m_slotMap.Empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Empty_ShouldReturnFalseIfTheSlotMapIsNotEmpty)
|
TYPED_TEST(SlotMapFixture, Empty_ShouldReturnFalseIfTheSlotMapIsNotEmpty)
|
||||||
{
|
{
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
EXPECT_FALSE(m_slotMap.Empty());
|
EXPECT_FALSE(this->m_slotMap.Empty());
|
||||||
|
|
||||||
m_slotMap.Clear();
|
this->m_slotMap.Clear();
|
||||||
|
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
std::ignore = m_slotMap.Insert(69);
|
std::ignore = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
EXPECT_FALSE(m_slotMap.Empty());
|
EXPECT_FALSE(this->m_slotMap.Empty());
|
||||||
|
|
||||||
m_slotMap.Reset();
|
this->m_slotMap.Reset();
|
||||||
|
|
||||||
const auto slotKey9 = m_slotMap.Insert(42);
|
const auto slotKey9 = this->m_slotMap.Insert(42);
|
||||||
EXPECT_FALSE(m_slotMap.Empty());
|
EXPECT_FALSE(this->m_slotMap.Empty());
|
||||||
m_slotMap.Remove(slotKey9);
|
this->m_slotMap.Remove(slotKey9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, Iterator)
|
TYPED_TEST(SlotMapFixture, Iterator)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
const auto slotKey3 = m_slotMap.Insert(28);
|
const auto slotKey3 = this->m_slotMap.Insert(28);
|
||||||
const auto slotKey4 = m_slotMap.Insert(0);
|
const auto slotKey4 = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey2);
|
this->m_slotMap.Remove(slotKey2);
|
||||||
|
|
||||||
eastl::vector<std::uint32_t> values;
|
eastl::vector<std::uint32_t> values;
|
||||||
for (auto it = m_slotMap.begin(); it != m_slotMap.end(); ++it)
|
for (auto it = this->m_slotMap.begin(); it != this->m_slotMap.end(); ++it)
|
||||||
{
|
{
|
||||||
values.push_back(*it);
|
values.push_back(*it);
|
||||||
}
|
}
|
||||||
@@ -374,28 +424,28 @@ TEST_F(SlotMapFixture, Iterator)
|
|||||||
EXPECT_EQ(values[2], 28);
|
EXPECT_EQ(values[2], 28);
|
||||||
|
|
||||||
// The non-const iterator is mutable.
|
// The non-const iterator is mutable.
|
||||||
for (std::uint32_t& value: m_slotMap)
|
for (std::uint32_t& value: this->m_slotMap)
|
||||||
{
|
{
|
||||||
value += 100;
|
value += 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey1), 142);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 142);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey3), 128);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey3), 128);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey4), 100);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey4), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, ConstIterator)
|
TYPED_TEST(SlotMapFixture, ConstIterator)
|
||||||
{
|
{
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey2);
|
this->m_slotMap.Remove(slotKey2);
|
||||||
|
|
||||||
const auto& constSlotMap = m_slotMap;
|
const auto& constSlotMap = this->m_slotMap;
|
||||||
|
|
||||||
eastl::vector<std::uint32_t> values;
|
eastl::vector<std::uint32_t> values;
|
||||||
for (auto it = constSlotMap.begin(); it != constSlotMap.end(); ++it)
|
for (auto it = constSlotMap.begin(); it != constSlotMap.end(); ++it)
|
||||||
@@ -410,7 +460,7 @@ TEST_F(SlotMapFixture, ConstIterator)
|
|||||||
|
|
||||||
// cbegin/cend yield the same const traversal.
|
// cbegin/cend yield the same const traversal.
|
||||||
eastl::vector<std::uint32_t> cValues;
|
eastl::vector<std::uint32_t> cValues;
|
||||||
for (auto it = m_slotMap.cbegin(); it != m_slotMap.cend(); ++it)
|
for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it)
|
||||||
{
|
{
|
||||||
cValues.push_back(*it);
|
cValues.push_back(*it);
|
||||||
}
|
}
|
||||||
@@ -420,17 +470,17 @@ TEST_F(SlotMapFixture, ConstIterator)
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, ReverseIterator)
|
TYPED_TEST(SlotMapFixture, ReverseIterator)
|
||||||
{
|
{
|
||||||
const auto slotKey1 = m_slotMap.Insert(42);
|
const auto slotKey1 = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
const auto slotKey3 = m_slotMap.Insert(28);
|
const auto slotKey3 = this->m_slotMap.Insert(28);
|
||||||
const auto slotKey4 = m_slotMap.Insert(0);
|
const auto slotKey4 = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey2);
|
this->m_slotMap.Remove(slotKey2);
|
||||||
|
|
||||||
eastl::vector<std::uint32_t> values;
|
eastl::vector<std::uint32_t> values;
|
||||||
for (auto it = m_slotMap.rbegin(); it != m_slotMap.rend(); ++it)
|
for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it)
|
||||||
{
|
{
|
||||||
values.push_back(*it);
|
values.push_back(*it);
|
||||||
}
|
}
|
||||||
@@ -441,28 +491,28 @@ TEST_F(SlotMapFixture, ReverseIterator)
|
|||||||
EXPECT_EQ(values[2], 42);
|
EXPECT_EQ(values[2], 42);
|
||||||
|
|
||||||
// The non-const reverse iterator is mutable.
|
// The non-const reverse iterator is mutable.
|
||||||
for (auto it = m_slotMap.rbegin(); it != m_slotMap.rend(); ++it)
|
for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it)
|
||||||
{
|
{
|
||||||
*it += 100;
|
*it += 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey1), 142);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey1), 142);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey3), 128);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey3), 128);
|
||||||
EXPECT_EQ(*m_slotMap.Get(slotKey4), 100);
|
EXPECT_EQ(*this->m_slotMap.Get(slotKey4), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SlotMapFixture, ConstReverseIterator)
|
TYPED_TEST(SlotMapFixture, ConstReverseIterator)
|
||||||
{
|
{
|
||||||
std::ignore = m_slotMap.Insert(42);
|
std::ignore = this->m_slotMap.Insert(42);
|
||||||
const auto slotKey2 = m_slotMap.Insert(69);
|
const auto slotKey2 = this->m_slotMap.Insert(69);
|
||||||
std::ignore = m_slotMap.Insert(28);
|
std::ignore = this->m_slotMap.Insert(28);
|
||||||
std::ignore = m_slotMap.Insert(0);
|
std::ignore = this->m_slotMap.Insert(0);
|
||||||
|
|
||||||
m_slotMap.Remove(slotKey2);
|
this->m_slotMap.Remove(slotKey2);
|
||||||
|
|
||||||
const auto& constSlotMap = m_slotMap;
|
const auto& constSlotMap = this->m_slotMap;
|
||||||
|
|
||||||
eastl::vector<std::uint32_t> values;
|
eastl::vector<std::uint32_t> values;
|
||||||
for (auto it = constSlotMap.rbegin(); it != constSlotMap.rend(); ++it)
|
for (auto it = constSlotMap.rbegin(); it != constSlotMap.rend(); ++it)
|
||||||
@@ -477,7 +527,7 @@ TEST_F(SlotMapFixture, ConstReverseIterator)
|
|||||||
|
|
||||||
// crbegin/crend yield the same const reverse traversal.
|
// crbegin/crend yield the same const reverse traversal.
|
||||||
eastl::vector<std::uint32_t> crValues;
|
eastl::vector<std::uint32_t> crValues;
|
||||||
for (auto it = m_slotMap.crbegin(); it != m_slotMap.crend(); ++it)
|
for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it)
|
||||||
{
|
{
|
||||||
crValues.push_back(*it);
|
crValues.push_back(*it);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,3 +152,102 @@ function(bigfoot_create_package_tests ParentFolder)
|
|||||||
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Fixture)
|
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Fixture)
|
||||||
set_target_properties(${PROJECT_NAME}Fixture PROPERTIES FOLDER UtilityTargets/Tests/Bigfoot/${ParentFolder})
|
set_target_properties(${PROJECT_NAME}Fixture PROPERTIES FOLDER UtilityTargets/Tests/Bigfoot/${ParentFolder})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
function(bigfoot_create_package_benchmarks ParentFolder)
|
||||||
|
add_executable(${PROJECT_NAME})
|
||||||
|
|
||||||
|
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
BigfootCompileAndLinkFlags
|
||||||
|
$<LINK_LIBRARY:WHOLE_ARCHIVE,${PackageName}>
|
||||||
|
benchmark::benchmark_main)
|
||||||
|
|
||||||
|
bigfoot_compile_flatbuffers()
|
||||||
|
|
||||||
|
file(GLOB_RECURSE _SOURCES
|
||||||
|
CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE _HEADERS
|
||||||
|
CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE _OTHERS
|
||||||
|
CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.fbs
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.sql
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${_SOURCES}
|
||||||
|
${_OTHERS}
|
||||||
|
PUBLIC
|
||||||
|
FILE_SET HEADERS
|
||||||
|
BASE_DIRS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Include
|
||||||
|
FILES
|
||||||
|
${_HEADERS}
|
||||||
|
)
|
||||||
|
|
||||||
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${_SOURCES} ${_HEADERS} ${_OTHERS})
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Benchmarks/Bigfoot/${ParentFolder})
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
|
||||||
|
|
||||||
|
##################ASAN SETUP###################
|
||||||
|
|
||||||
|
if(${ASAN})
|
||||||
|
if(MSVC)
|
||||||
|
get_filename_component(MSVC_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
|
||||||
|
set(ASAN_DLL "${MSVC_BIN_DIR}/clang_rt.asan_dynamic-x86_64.dll")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp"
|
||||||
|
DEPENDS "${ASAN_DLL}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ASAN_DLL}" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp"
|
||||||
|
COMMENT "Copying ASan DLL for ${PROJECT_NAME}"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(${PROJECT_NAME}Asan
|
||||||
|
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Asan)
|
||||||
|
set_target_properties(${PROJECT_NAME}Asan PROPERTIES FOLDER UtilityTargets/Benchmarks/Bigfoot/${ParentFolder})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
##################COPY FIXTURE FOLDER###################
|
||||||
|
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Fixture)
|
||||||
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Fixture)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GLOB_RECURSE FIXTURE_FILES
|
||||||
|
CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Fixture/*
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp"
|
||||||
|
DEPENDS ${FIXTURE_FILES}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E remove_directory $<TARGET_FILE_DIR:${PROJECT_NAME}>/Fixture
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Fixture $<TARGET_FILE_DIR:${PROJECT_NAME}>/Fixture
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp"
|
||||||
|
COMMENT "Copying Fixture folder for ${PROJECT_NAME}"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(${PROJECT_NAME}Fixture
|
||||||
|
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Fixture)
|
||||||
|
set_target_properties(${PROJECT_NAME}Fixture PROPERTIES FOLDER UtilityTargets/Benchmarks/Bigfoot/${ParentFolder})
|
||||||
|
endfunction()
|
||||||
@@ -47,6 +47,9 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Sources)
|
|||||||
if(${BUILD_TESTS})
|
if(${BUILD_TESTS})
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Tests)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Tests)
|
||||||
endif()
|
endif()
|
||||||
|
if(${BUILD_BENCHMARKS})
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Benchmarks)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_target(NatVis SOURCES
|
add_custom_target(NatVis SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Vendor/NatVis/EASTL/EASTL.natvis
|
${CMAKE_CURRENT_SOURCE_DIR}/Vendor/NatVis/EASTL/EASTL.natvis
|
||||||
|
|||||||
Reference in New Issue
Block a user