From 6d1d7fc6b9d5b99968eecadbd18a46752a8694c5 Mon Sep 17 00:00:00 2001 From: jadebenn Date: Wed, 24 Jan 2024 21:46:28 -0600 Subject: [PATCH] variadic inheritance (yes, really) --- dCommon/CMakeLists.txt | 1 + {thirdparty/MD5 => dCommon}/MD5.cpp | 0 {thirdparty/MD5 => dCommon}/MD5.h | 0 dGame/dEntity/Archetype.h | 113 ++++++++---------- .../dEntitiesTests/ArchetypeTests.cpp | 20 ++-- thirdparty/CMakeLists.txt | 3 - thirdparty/MD5/CMakeLists.txt | 5 - 7 files changed, 60 insertions(+), 82 deletions(-) rename {thirdparty/MD5 => dCommon}/MD5.cpp (100%) rename {thirdparty/MD5 => dCommon}/MD5.h (100%) delete mode 100644 thirdparty/MD5/CMakeLists.txt diff --git a/dCommon/CMakeLists.txt b/dCommon/CMakeLists.txt index 00c336260..fec1a2d70 100644 --- a/dCommon/CMakeLists.txt +++ b/dCommon/CMakeLists.txt @@ -8,6 +8,7 @@ set(DCOMMON_SOURCES "Game.cpp" "GeneralUtils.cpp" "LDFFormat.cpp" + "MD5.cpp" "Metrics.cpp" "NiPoint3.cpp" "NiQuaternion.cpp" diff --git a/thirdparty/MD5/MD5.cpp b/dCommon/MD5.cpp similarity index 100% rename from thirdparty/MD5/MD5.cpp rename to dCommon/MD5.cpp diff --git a/thirdparty/MD5/MD5.h b/dCommon/MD5.h similarity index 100% rename from thirdparty/MD5/MD5.h rename to dCommon/MD5.h diff --git a/dGame/dEntity/Archetype.h b/dGame/dEntity/Archetype.h index e8129b848..57ad874fc 100644 --- a/dGame/dEntity/Archetype.h +++ b/dGame/dEntity/Archetype.h @@ -1,6 +1,7 @@ #ifndef __ARCHETYPE_H__ #define __ARCHETYPE_H__ +#include #include #include #include @@ -10,13 +11,28 @@ // Require the template type to be of component base class template -concept ComponentType = std::is_base_of_v; +concept ComponentType = std::derived_from; + +// Forward declaration of archetype class +template +class Archetype; + +// Container struct for storing component data +template +struct Container { + using type = T; // Alias to allow retrieval of entry type + + using storage_type = std::vector; //Alias for the archetype component container type + //using storage_type = std::array; + + storage_type entries; +}; /** * Base class to allow pointer/reference resolution * Contains less-performant versions of methods to allow runtime resolution of component types */ -class IArchetype { +class ArchetypeBase { public: /** * Create an alias type for the Archetype ID @@ -24,19 +40,13 @@ class IArchetype { using ArchetypeId = size_t; ArchetypeId id{ 0 }; - /** - * Create an alias for the archetype component container type - */ - template - using ContainerType = std::vector; - /** * Check if a component type is contained by the archetype * @returns Boolean value representing whether the component type is present in the archetype */ template [[nodiscard]] bool HasComponent() noexcept { - return m_ContainerPointers.contains(std::type_index(typeid(CType))) != 0; + return dynamic_cast&>(*this).template HasComponent(); // TODO: Change this method! } /** @@ -44,50 +54,39 @@ class IArchetype { * @returns A reference to the component container */ template - [[nodiscard]] ContainerType& Container() { - return *reinterpret_cast*>(m_ContainerPointers[std::type_index(typeid(CType))]); + [[nodiscard]] Container::storage_type& GetContainer() { // TODO: Try to avoid using this! + return dynamic_cast&>(*this).template Container::entries; } - virtual ~IArchetype() = default; + virtual ~ArchetypeBase() = default; protected: - IArchetype(ArchetypeId id) noexcept : id{ id } {} + ArchetypeBase() = default; - /** - * Unordered map containing void pointers to each container - */ - std::unordered_map m_ContainerPointers; + constexpr explicit ArchetypeBase(ArchetypeId id) noexcept : id{ id } {}; }; /** * The archetype class stores a variable number of entity component types TODO: EXPAND ON */ template -class Archetype final : public IArchetype { +class Archetype final : public ArchetypeBase, public Container... { public: - constexpr explicit Archetype(ArchetypeId id) noexcept : IArchetype{ id } { + /** + * Alias that extracts the type of the Nth element passed as a template argument + */ + template + using type_index = std::tuple_element>::type; + + /** + * Constructor + */ + constexpr explicit Archetype(ArchetypeId id) noexcept : ArchetypeBase{ id } { // Reserve 16 KB of memory for the sum of all vectors ahead of time constexpr size_t compBytes = (sizeof(CTypes) + ...); constexpr size_t reservedBytes = 16000; constexpr size_t reserveNumEntries = reservedBytes / compBytes; - (Container().reserve(reserveNumEntries), ...); - - // Create void pointers to each component container present - (m_ContainerPointers.emplace(typeid(CTypes), reinterpret_cast(&Container())), ...); - } - - /** - * Constructors and assignment operators - */ - Archetype(Archetype& other) noexcept : IArchetype{ std::copy(other) } { /*UpdatePointers();*/ } // Copy constructor - Archetype(Archetype&& other) noexcept : IArchetype{ std::move(other) } { /*UpdatePointers();*/ } // Move constructor - Archetype& operator=(Archetype& other) noexcept { // Copy assignment operator - IArchetype::operator=(std::copy(other)); - /*UpdatePointers();*/ - } - Archetype& operator=(Archetype&& other) noexcept { // Move assignment operator - IArchetype::operator=(std::move(other)); - /*UpdatePointers();*/ + (Container::entries.reserve(reserveNumEntries), ...); } /** @@ -95,7 +94,8 @@ class Archetype final : public IArchetype { * @returns The size of the archetype's containers */ [[nodiscard]] constexpr size_t size() noexcept { - return std::get<0>(m_Components).size(); + Container>::entries.size(); + return Container>::entries.size(); } /** @@ -103,36 +103,26 @@ class Archetype final : public IArchetype { * @returns Boolean representing whether the container is empty */ [[nodiscard]] constexpr bool empty() noexcept { - return std::get<0>(m_Components).empty(); - } - - /** - * Get a reference to the component container of an archetype. - * @returns A reference to the archetype's container of components - */ - template - [[nodiscard]] constexpr ContainerType& Container() noexcept { - static_assert(HasComponent(), "Archetype does not have container of requested component!"); // Compile-time verification - return std::get>(m_Components); + return Container>::entries.empty(); } /** * Creates the archetype's components at the end of the container. * @param componentArgs Arguments to be forwarded to the component constructors */ - void CreateComponents(CTypes&&... componentArgs) noexcept { - (Container().emplace_back(std::forward(componentArgs)), ...); + constexpr void CreateComponents(CTypes&&... componentArgs) noexcept { + (Container::entries.emplace_back(std::forward(componentArgs)), ...); } /** * Delete's the archetype's components at a specified container index, then moves the last element in the container to it. * @param index The archetype container index to delete */ - void DeleteComponents(const size_t index) { + constexpr void DeleteComponents(const size_t index) { if (empty()) return; // Do not delete if the container is already empty - ((Container().at(index) = std::move(Container().back()), - Container().pop_back()), ...); + ((Container::entries.at(index) = std::move(Container::entries.back()), + Container::entries.pop_back()), ...); } /** @@ -142,7 +132,7 @@ class Archetype final : public IArchetype { */ template [[nodiscard]] CType& GetComponent(const size_t index) { - return Container().at(index); + return Container::entries.at(index); } /** @@ -157,20 +147,15 @@ class Archetype final : public IArchetype { /** * Contains the number of component types an archetype consists of */ - static constexpr size_t numTypes = sizeof...(CTypes); + static constexpr size_t num_types = sizeof...(CTypes); template struct contains : std::disjunction...> {}; -private: - /** - * Update void pointer locations in memory (to be called by move and copy constructors) - */ - constexpr void UpdatePointers() noexcept { - ((m_ContainerPointers[std::type_index(typeid(CTypes))] = reinterpret_cast(Container())), ...); - } + template + using contains_v = contains::value; - std::tuple...> m_Components; // Made it a tuple of vectors (may God help us all) +private: //std::unordered_map> edges; }; diff --git a/tests/dGameTests/dEntitiesTests/ArchetypeTests.cpp b/tests/dGameTests/dEntitiesTests/ArchetypeTests.cpp index 85eba1edd..119cfa2f7 100644 --- a/tests/dGameTests/dEntitiesTests/ArchetypeTests.cpp +++ b/tests/dGameTests/dEntitiesTests/ArchetypeTests.cpp @@ -76,7 +76,7 @@ TEST_F(ArchetypeTest, PlacementNewAddArchetypeTest) { size_t destCompSize = sizeof(baseArchetype->GetComponent(1)); LOG("Destroyable component is of %ul size!", destCompSize); - auto nEntries = baseArchetype->Container().capacity(); + auto nEntries = baseArchetype->Container::entries.capacity(); LOG("Archetype has %d entries!", nEntries); } @@ -131,7 +131,7 @@ TEST_F(ArchetypeTest, ArchetypeDeleteTest) { /*TEST_F(ArchetypeTest, AddEntityTest) { // Create the archetypes - std::array, 3> tempArchetype; + std::array, 3> tempArchetype; tempArchetype[0] = std::make_unique>(1); tempArchetype[1] = std::make_unique>(2); tempArchetype[2] = std::make_unique>(3); @@ -221,17 +221,17 @@ TEST_F(ArchetypeTest, CreateArchetypesTest) { ASSERT_EQ(gottenEntityId, baseEntityId); }*/ -TEST_F(ArchetypeTest, MoveIArchetypeTest) { +TEST_F(ArchetypeTest, MoveArchetypeBaseTest) { // Insert an entry into the base archetype and set one trait for each const auto baseEntityId = baseEntity->GetObjectID(); baseArchetype->CreateComponents(DestroyableComponent(baseEntityId), SimplePhysicsComponent(baseEntityId, 2)); - baseArchetype->Container()[0].SetMaxHealth(30); - baseArchetype->Container()[0].SetPosition(NiPoint3(1.0f, 2.0f, 3.0f)); + baseArchetype->Container::entries[0].SetMaxHealth(30); + baseArchetype->Container::entries[0].SetPosition(NiPoint3(1.0f, 2.0f, 3.0f)); // Move the archetype and compare the entry results, as well as checking the original is deleted - std::unique_ptr movedArchetype = std::move(baseArchetype); - ASSERT_FLOAT_EQ(movedArchetype->Container()[0].GetMaxHealth(), 30); - ASSERT_EQ(movedArchetype->Container()[0].GetPosition(), NiPoint3(1.0f, 2.0f, 3.0f)); + std::unique_ptr movedArchetype = std::move(baseArchetype); + ASSERT_FLOAT_EQ(movedArchetype->GetContainer()[0].GetMaxHealth(), 30); + ASSERT_EQ(movedArchetype->GetContainer()[0].GetPosition(), NiPoint3(1.0f, 2.0f, 3.0f)); ASSERT_EQ(baseArchetype.get(), nullptr); } @@ -287,11 +287,11 @@ namespace { template struct ContainerVisitor { - std::vector* const operator()(auto&& archetype) { + Container::storage_type* const operator()(auto&& archetype) { using ArchetypeType = std::remove_pointer_t>; // Needed to fix a MacOS issue if constexpr (!ArchetypeType::template HasComponent()) return nullptr; - else return &archetype->template Container(); + else return &archetype->template Container::entries; } }; } diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index c2e1e71f1..11d278c08 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -28,9 +28,6 @@ add_subdirectory(SQLite) # Source code for magic_enum add_subdirectory(magic_enum) -# Source code for MD5 -add_subdirectory(MD5) - # MariaDB C++ Connector include(CMakeMariaDBLists.txt) diff --git a/thirdparty/MD5/CMakeLists.txt b/thirdparty/MD5/CMakeLists.txt deleted file mode 100644 index f54e97124..000000000 --- a/thirdparty/MD5/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(MD5_SOURCES - "MD5.cpp" -) - -add_library(MD5 ${MD5_SOURCES})