From eaaf1911b361ef498f25b9777239618552427362 Mon Sep 17 00:00:00 2001 From: jnyfah Date: Tue, 25 Mar 2025 22:13:09 +0100 Subject: [PATCH 1/9] hash map???? --- .gitmodules | 3 + CMakeLists.txt | 1 + Tetragrama/Components/UIComponent.h | 14 +- Tetragrama/Editor.cpp | 2 +- Tetragrama/Editor.h | 24 +- Tetragrama/EditorWindow.cpp | 4 +- Tetragrama/EditorWindow.h | 4 +- Tetragrama/Helpers/SerializerCommonHelper.cpp | 10 +- Tetragrama/Helpers/SerializerCommonHelper.h | 12 +- Tetragrama/Importers/AssimpImporter.cpp | 2 +- Tetragrama/Importers/IAssetImporter.h | 24 +- Tetragrama/Layers/ImguiLayer.cpp | 2 +- Tetragrama/Layers/ImguiLayer.h | 8 +- .../Serializers/EditorSceneSerializer.cpp | 4 +- ZEngine/ZEngine/CMakeLists.txt | 2 +- .../Core/{Container => Containers}/Array.h | 4 +- ZEngine/ZEngine/Core/Containers/HashMap.h | 212 ++++++++++++++++++ .../Core/{Container => Containers}/Strings.h | 4 +- ZEngine/ZEngine/Windows/CoreWindow.h | 38 ++-- ZEngine/ZEngine/Windows/Layers/LayerStack.h | 4 +- ZEngine/ZEngine/Windows/WindowConfiguration.h | 16 +- ZEngine/ZEngine/Windows/WindowProperty.h | 2 +- ZEngine/ZEngine/ZEngineDef.h | 2 +- ZEngine/tests/CMakeLists.txt | 1 + ZEngine/tests/array_test.cpp | 4 +- ZEngine/tests/hashmap_test.cpp | 151 +++++++++++++ ZEngine/tests/string_test.cpp | 4 +- __externals/externals.cmake | 2 + __externals/rapidhash/CMakeLists.txt | 11 + __externals/rapidhash/src | 1 + 30 files changed, 477 insertions(+), 95 deletions(-) rename ZEngine/ZEngine/Core/{Container => Containers}/Array.h (98%) create mode 100644 ZEngine/ZEngine/Core/Containers/HashMap.h rename ZEngine/ZEngine/Core/{Container => Containers}/Strings.h (98%) create mode 100644 ZEngine/tests/hashmap_test.cpp create mode 100644 __externals/rapidhash/CMakeLists.txt create mode 160000 __externals/rapidhash/src diff --git a/.gitmodules b/.gitmodules index 4a73610e..2eaffaf6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -64,3 +64,6 @@ [submodule "__externals/CLI11"] path = __externals/CLI11 url = https://github.com/CLIUtils/CLI11 +[submodule "__externals/rapidhash/src"] + path = __externals/rapidhash/src + url = https://github.com/Nicoshev/rapidhash diff --git a/CMakeLists.txt b/CMakeLists.txt index 57ec0235..2da817d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ if (NOT LAUNCHER_ONLY) add_subdirectory (${EXTERNAL_DIR}/gtest) add_subdirectory (${EXTERNAL_DIR}/VulkanMemoryAllocator) add_subdirectory (${EXTERNAL_DIR}/tlsf) + add_subdirectory (${EXTERNAL_DIR}/rapidhash) add_subdirectory (${EXTERNAL_DIR}/CLI11) set (CMAKE_PREFIX_PATH diff --git a/Tetragrama/Components/UIComponent.h b/Tetragrama/Components/UIComponent.h index 047aac76..58932d9b 100644 --- a/Tetragrama/Components/UIComponent.h +++ b/Tetragrama/Components/UIComponent.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include @@ -24,11 +24,11 @@ namespace Tetragrama::Components CanBeClosed = closed; } - bool IsVisible = true; - bool CanBeClosed = false; - const char* Name = ""; - uint32_t ChildrenCount = 0; - Tetragrama::Layers::ImguiLayer* ParentLayer = nullptr; - ZEngine::Core::Container::Array Children = {}; + bool IsVisible = true; + bool CanBeClosed = false; + const char* Name = ""; + uint32_t ChildrenCount = 0; + Tetragrama::Layers::ImguiLayer* ParentLayer = nullptr; + ZEngine::Core::Containers::Array Children = {}; }; } // namespace Tetragrama::Components diff --git a/Tetragrama/Editor.cpp b/Tetragrama/Editor.cpp index 82c861e0..e3b71764 100644 --- a/Tetragrama/Editor.cpp +++ b/Tetragrama/Editor.cpp @@ -6,7 +6,7 @@ #include using namespace ZEngine; -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; using namespace ZEngine::Core::Memory; using namespace ZEngine::Helpers; using namespace Tetragrama::Layers; diff --git a/Tetragrama/Editor.h b/Tetragrama/Editor.h index 1d7630dc..dd84e128 100644 --- a/Tetragrama/Editor.h +++ b/Tetragrama/Editor.h @@ -2,8 +2,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -23,19 +23,19 @@ namespace Tetragrama EditorScene() = default; - void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, const char* scene_name = ""); - void Push(ZEngine::Core::Memory::ArenaAllocator* arena, const char* mesh, const char* model, const char* material); - bool HasPendingChange() const; + void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, const char* scene_name = ""); + void Push(ZEngine::Core::Memory::ArenaAllocator* arena, const char* mesh, const char* model, const char* material); + bool HasPendingChange() const; - const char* Name = ""; - ZEngine::Core::Container::Array MeshFiles = {}; - ZEngine::Core::Container::Array ModelFiles = {}; - ZEngine::Core::Container::Array MaterialFiles = {}; + const char* Name = ""; + ZEngine::Core::Containers::Array MeshFiles = {}; + ZEngine::Core::Containers::Array ModelFiles = {}; + ZEngine::Core::Containers::Array MaterialFiles = {}; - ZEngine::Core::Container::Array Hashes = {}; - std::map Data = {}; + ZEngine::Core::Containers::Array Hashes = {}; + std::map Data = {}; - ZRawPtr(ZEngine::Rendering::Scenes::GraphicScene) RenderScene = nullptr; + ZRawPtr(ZEngine::Rendering::Scenes::GraphicScene) RenderScene = nullptr; private: std::atomic_bool m_has_pending_change; diff --git a/Tetragrama/EditorWindow.cpp b/Tetragrama/EditorWindow.cpp index 5debc691..e0aa26c6 100644 --- a/Tetragrama/EditorWindow.cpp +++ b/Tetragrama/EditorWindow.cpp @@ -38,7 +38,7 @@ namespace Tetragrama return m_property.Width; } - ZEngine::Core::Container::StringView EditorWindow::GetTitle() const + ZEngine::Core::Containers::StringView EditorWindow::GetTitle() const { return m_property.Title; } @@ -48,7 +48,7 @@ namespace Tetragrama return m_property.IsMinimized; } - void EditorWindow::SetTitle(ZEngine::Core::Container::StringView title) + void EditorWindow::SetTitle(ZEngine::Core::Containers::StringView title) { m_property.Title = title.data(); glfwSetWindowTitle(m_native_window, m_property.Title); diff --git a/Tetragrama/EditorWindow.h b/Tetragrama/EditorWindow.h index 7e2414de..3257f9b1 100644 --- a/Tetragrama/EditorWindow.h +++ b/Tetragrama/EditorWindow.h @@ -17,9 +17,9 @@ namespace Tetragrama uint32_t GetHeight() const override; uint32_t GetWidth() const override; - ZEngine::Core::Container::StringView GetTitle() const override; + ZEngine::Core::Containers::StringView GetTitle() const override; bool IsMinimized() const override; - void SetTitle(ZEngine::Core::Container::StringView title) override; + void SetTitle(ZEngine::Core::Containers::StringView title) override; bool IsVSyncEnable() const override; void SetVSync(bool value) override; void SetCallbackFunction(const EventCallbackFn& callback) override; diff --git a/Tetragrama/Helpers/SerializerCommonHelper.cpp b/Tetragrama/Helpers/SerializerCommonHelper.cpp index f0042d38..3ac29684 100644 --- a/Tetragrama/Helpers/SerializerCommonHelper.cpp +++ b/Tetragrama/Helpers/SerializerCommonHelper.cpp @@ -2,18 +2,18 @@ #include #include -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; namespace Tetragrama::Helpers { - void SerializeStringData(std::ostream& os, ZEngine::Core::Container::StringView str) + void SerializeStringData(std::ostream& os, ZEngine::Core::Containers::StringView str) { size_t f_count = str.size(); os.write(reinterpret_cast(&f_count), sizeof(size_t)); os.write(str.data(), f_count + 1); } - void DeserializeStringData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, ZEngine::Core::Container::String& d) + void DeserializeStringData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, ZEngine::Core::Containers::String& d) { size_t v_count; in.read(reinterpret_cast(&v_count), sizeof(size_t)); @@ -22,7 +22,7 @@ namespace Tetragrama::Helpers in.read(d.data(), v_count + 1); } - void SerializeStringArrayData(std::ostream& os, ZEngine::Core::Container::ArrayView str_view) + void SerializeStringArrayData(std::ostream& os, ZEngine::Core::Containers::ArrayView str_view) { size_t count = str_view.size(); os.write(reinterpret_cast(&count), sizeof(size_t)); @@ -49,7 +49,7 @@ namespace Tetragrama::Helpers os.write(reinterpret_cast(flat_data.data()), sizeof(uint32_t) * flat_data.size()); } - void DeserializeStringArrayData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, ZEngine::Core::Container::Array& data) + void DeserializeStringArrayData(ZEngine::Core::Memory::ArenaAllocator* Arena, std::istream& in, ZEngine::Core::Containers::Array& data) { size_t data_count; in.read(reinterpret_cast(&data_count), sizeof(size_t)); diff --git a/Tetragrama/Helpers/SerializerCommonHelper.h b/Tetragrama/Helpers/SerializerCommonHelper.h index 885e2ad6..2ab41dea 100644 --- a/Tetragrama/Helpers/SerializerCommonHelper.h +++ b/Tetragrama/Helpers/SerializerCommonHelper.h @@ -1,17 +1,17 @@ #pragma once -#include -#include +#include +#include #include #include #include namespace Tetragrama::Helpers { - void SerializeStringData(std::ostream&, ZEngine::Core::Container::StringView); - void SerializeStringArrayData(std::ostream&, ZEngine::Core::Container::ArrayView); + void SerializeStringData(std::ostream&, ZEngine::Core::Containers::StringView); + void SerializeStringArrayData(std::ostream&, ZEngine::Core::Containers::ArrayView); void SerializeMapData(std::ostream&, const std::unordered_map&); - void DeserializeStringData(ZEngine::Core::Memory::ArenaAllocator*, std::istream& in, ZEngine::Core::Container::String& data); - void DeserializeStringArrayData(ZEngine::Core::Memory::ArenaAllocator*, std::istream&, ZEngine::Core::Container::Array&); + void DeserializeStringData(ZEngine::Core::Memory::ArenaAllocator*, std::istream& in, ZEngine::Core::Containers::String& data); + void DeserializeStringArrayData(ZEngine::Core::Memory::ArenaAllocator*, std::istream&, ZEngine::Core::Containers::Array&); void DeserializeMapData(ZEngine::Core::Memory::ArenaAllocator*, std::istream&, std::unordered_map&); } // namespace Tetragrama::Helpers \ No newline at end of file diff --git a/Tetragrama/Importers/AssimpImporter.cpp b/Tetragrama/Importers/AssimpImporter.cpp index 974ec59a..6d066de2 100644 --- a/Tetragrama/Importers/AssimpImporter.cpp +++ b/Tetragrama/Importers/AssimpImporter.cpp @@ -11,7 +11,7 @@ using namespace ZEngine::Helpers; using namespace Tetragrama::Helpers; using namespace ZEngine::Rendering::Meshes; using namespace ZEngine::Rendering::Scenes; -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; namespace fs = std::filesystem; diff --git a/Tetragrama/Importers/IAssetImporter.h b/Tetragrama/Importers/IAssetImporter.h index 55b684da..ccf9815c 100644 --- a/Tetragrama/Importers/IAssetImporter.h +++ b/Tetragrama/Importers/IAssetImporter.h @@ -2,8 +2,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -25,20 +25,20 @@ namespace Tetragrama::Importers uint32_t VertexOffset = 0; uint32_t IndexOffset = 0; ZEngine::Rendering::Scenes::SceneRawData Scene = {}; - ZEngine::Core::Container::String Name = {}; - ZEngine::Core::Container::String SerializedMeshesPath = {}; - ZEngine::Core::Container::String SerializedMaterialsPath = {}; - ZEngine::Core::Container::String SerializedModelPath = {}; + ZEngine::Core::Containers::String Name = {}; + ZEngine::Core::Containers::String SerializedMeshesPath = {}; + ZEngine::Core::Containers::String SerializedMaterialsPath = {}; + ZEngine::Core::Containers::String SerializedModelPath = {}; }; struct ImportConfiguration { - ZEngine::Core::Container::String AssetFilename; - ZEngine::Core::Container::String InputBaseAssetFilePath; - ZEngine::Core::Container::String OutputModelFilePath; - ZEngine::Core::Container::String OutputMeshFilePath; - ZEngine::Core::Container::String OutputTextureFilesPath; - ZEngine::Core::Container::String OutputMaterialsPath; + ZEngine::Core::Containers::String AssetFilename; + ZEngine::Core::Containers::String InputBaseAssetFilePath; + ZEngine::Core::Containers::String OutputModelFilePath; + ZEngine::Core::Containers::String OutputMeshFilePath; + ZEngine::Core::Containers::String OutputTextureFilesPath; + ZEngine::Core::Containers::String OutputMaterialsPath; }; struct IAssetImporter diff --git a/Tetragrama/Layers/ImguiLayer.cpp b/Tetragrama/Layers/ImguiLayer.cpp index e3e82ed6..30158f9c 100644 --- a/Tetragrama/Layers/ImguiLayer.cpp +++ b/Tetragrama/Layers/ImguiLayer.cpp @@ -17,7 +17,7 @@ using namespace ZEngine; using namespace ZEngine::Rendering::Renderers; using namespace ZEngine::Windows::Events; -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; using namespace ZEngine::Helpers; using namespace Tetragrama::Messengers; diff --git a/Tetragrama/Layers/ImguiLayer.h b/Tetragrama/Layers/ImguiLayer.h index 263671de..f348dc69 100644 --- a/Tetragrama/Layers/ImguiLayer.h +++ b/Tetragrama/Layers/ImguiLayer.h @@ -1,7 +1,7 @@ #pragma once #include -#include -#include +#include +#include #include #include #include @@ -28,8 +28,8 @@ namespace Tetragrama::Layers ImguiLayer(const char* name = "ImGUI Layer") : Layer(name) {} virtual ~ImguiLayer(); - ZEngine::Core::Container::Array NodeHierarchies = {}; - ZEngine::Core::Container::Array NodeToRender = {}; + ZEngine::Core::Containers::Array NodeHierarchies = {}; + ZEngine::Core::Containers::Array NodeToRender = {}; std::map NodeUIComponents = {}; virtual void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena) override; diff --git a/Tetragrama/Serializers/EditorSceneSerializer.cpp b/Tetragrama/Serializers/EditorSceneSerializer.cpp index 3b75da34..9bdb7dc1 100644 --- a/Tetragrama/Serializers/EditorSceneSerializer.cpp +++ b/Tetragrama/Serializers/EditorSceneSerializer.cpp @@ -3,11 +3,11 @@ #include #include #include -#include +#include #include using namespace ZEngine::Helpers; -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; using namespace Tetragrama::Helpers; using namespace Tetragrama::Importers; diff --git a/ZEngine/ZEngine/CMakeLists.txt b/ZEngine/ZEngine/CMakeLists.txt index 008db05b..35f88550 100644 --- a/ZEngine/ZEngine/CMakeLists.txt +++ b/ZEngine/ZEngine/CMakeLists.txt @@ -23,7 +23,7 @@ target_include_directories (zEngineLib . ./Core ./Core/Memory - ./Core/Container + ./Core/Containers ./Hardwares ./Helpers ./Layers diff --git a/ZEngine/ZEngine/Core/Container/Array.h b/ZEngine/ZEngine/Core/Containers/Array.h similarity index 98% rename from ZEngine/ZEngine/Core/Container/Array.h rename to ZEngine/ZEngine/Core/Containers/Array.h index 9f013f84..e6630f4e 100644 --- a/ZEngine/ZEngine/Core/Container/Array.h +++ b/ZEngine/ZEngine/Core/Containers/Array.h @@ -6,7 +6,7 @@ using namespace ZEngine::Core::Memory; -namespace ZEngine::Core::Container +namespace ZEngine::Core::Containers { template @@ -219,4 +219,4 @@ namespace ZEngine::Core::Container T* m_data; size_t m_size; }; -} // namespace ZEngine::Core::Container \ No newline at end of file +} // namespace ZEngine::Core::Containers \ No newline at end of file diff --git a/ZEngine/ZEngine/Core/Containers/HashMap.h b/ZEngine/ZEngine/Core/Containers/HashMap.h new file mode 100644 index 00000000..9bffa670 --- /dev/null +++ b/ZEngine/ZEngine/Core/Containers/HashMap.h @@ -0,0 +1,212 @@ +#pragma once +#include +#include +#include +#include + +using namespace ZEngine::Core::Memory; + +namespace ZEngine::Core::Containers +{ + template + struct HashMap + { + struct Node + { + K key; + V value; + Node* next = nullptr; + }; + + struct KeyValue + { + Node* head = nullptr; + }; + + void init(Memory::ArenaAllocator* allocator, size_t initial_capacity, size_t initial_size = 0U) + { + m_allocator = allocator; + m_size = initial_size; + m_capacity = 0; + m_data = nullptr; + reserve(initial_capacity); + } + + void insert(const K& key, const V& value) + { + if (m_size >= m_capacity * 0.75) + { + reserve(m_capacity ? m_capacity * 2 : 8); + } + + size_t index = hash(key); + Node* current = m_data[index].head; + + while (current) + { + if (current->key == key) + { + current->value = value; + return; + } + current = current->next; + } + + Node* new_node = static_cast(ZAlloc(m_allocator, sizeof(Node), ZAlignof(Node))); + new_node->key = key; + new_node->value = value; + new_node->next = m_data[index].head; + m_data[index].head = new_node; + + ++m_size; + } + + bool contains(const K& key) + { + return find(key) != nullptr; + } + + V& operator[](const K& key) + { + size_t index = hash(key); + Node* current = m_data[index].head; + + while (current) + { + if (current->key == key) + { + return current->value; + } + current = current->next; + } + + if (m_size >= m_capacity * 0.75) + { + reserve(m_capacity ? m_capacity * 2 : 8); + index = hash(key); // Recompute after reserve + } + + Node* new_node = static_cast(ZAlloc(m_allocator, sizeof(Node), ZAlignof(Node))); + new_node->key = key; + new_node->value = V{}; + new_node->next = m_data[index].head; + m_data[index].head = new_node; + + ++m_size; + return new_node->value; + } + + V* find(const K& key) + { + size_t index = hash(key); + Node* current = m_data[index].head; + + while (current) + { + if (current->key == key) + { + return ¤t->value; + } + current = current->next; + } + return nullptr; + } + + void remove(const K& key) + { + size_t index = hash(key); + Node* current = m_data[index].head; + Node* prev = nullptr; + + while (current) + { + if (current->key == key) + { + if (prev) + prev->next = current->next; + else + m_data[index].head = current->next; + --m_size; + return; + } + prev = current; + current = current->next; + } + } + + ~HashMap() + { + clear(); + if (m_data) + { + m_data = nullptr; + } + } + + void clear() + { + for (size_t i = 0; i < m_capacity; ++i) + { + Node* current = m_data[i].head; + while (current) + { + Node* next = current->next; + // Optionally free current node here + current = next; + } + m_data[i].head = nullptr; + } + m_size = 0; + } + + void reserve(size_t new_capacity) + { + KeyValue* old_data = m_data; + size_t old_capacity = m_capacity; + + m_data = static_cast(ZAlloc(m_allocator, new_capacity * sizeof(KeyValue), ZAlignof(KeyValue))); + Helpers::secure_memset(m_data, 0, new_capacity * sizeof(KeyValue), m_capacity); + + m_capacity = new_capacity; + + for (size_t i = 0; i < old_capacity; ++i) + { + Node* current = old_data[i].head; + while (current) + { + Node* next = current->next; + + size_t new_index = hash(current->key); // Now uses new m_capacity + current->next = m_data[new_index].head; + m_data[new_index].head = current; + + current = next; + } + } + } + + size_t size() const + { + return m_size; + } + size_t capacity() const + { + return m_capacity; + } + bool empty() const + { + return m_size == 0; + } + + size_t hash(const K& key) const + { + return rapidhash(&key, sizeof(K)) % m_capacity; + } + + Memory::ArenaAllocator* m_allocator = nullptr; + size_t m_size = 0; + size_t m_capacity = 0; + KeyValue* m_data = nullptr; + }; + +} // namespace ZEngine::Core::Containers diff --git a/ZEngine/ZEngine/Core/Container/Strings.h b/ZEngine/ZEngine/Core/Containers/Strings.h similarity index 98% rename from ZEngine/ZEngine/Core/Container/Strings.h rename to ZEngine/ZEngine/Core/Containers/Strings.h index b2de00ee..984a914c 100644 --- a/ZEngine/ZEngine/Core/Container/Strings.h +++ b/ZEngine/ZEngine/Core/Containers/Strings.h @@ -2,7 +2,7 @@ #include #include -namespace ZEngine::Core::Container +namespace ZEngine::Core::Containers { struct String { @@ -252,4 +252,4 @@ namespace ZEngine::Core::Container size_type m_size; }; -} // namespace ZEngine::Core::Container \ No newline at end of file +} // namespace ZEngine::Core::Containers \ No newline at end of file diff --git a/ZEngine/ZEngine/Windows/CoreWindow.h b/ZEngine/ZEngine/Windows/CoreWindow.h index 9eef2c69..f2c9874c 100644 --- a/ZEngine/ZEngine/Windows/CoreWindow.h +++ b/ZEngine/ZEngine/Windows/CoreWindow.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include @@ -36,30 +36,30 @@ namespace ZEngine::Windows CoreWindow(const WindowConfiguration& cfg); virtual ~CoreWindow(); - virtual uint32_t GetHeight() const = 0; - virtual uint32_t GetWidth() const = 0; - virtual Core::Container::StringView GetTitle() const = 0; - virtual void SetTitle(Core::Container::StringView title) = 0; - virtual bool IsMinimized() const = 0; + virtual uint32_t GetHeight() const = 0; + virtual uint32_t GetWidth() const = 0; + virtual Core::Containers::StringView GetTitle() const = 0; + virtual void SetTitle(Core::Containers::StringView title) = 0; + virtual bool IsMinimized() const = 0; - virtual bool IsVSyncEnable() const = 0; - virtual void SetVSync(bool value) = 0; - virtual void SetCallbackFunction(const EventCallbackFn& callback) = 0; - virtual const WindowProperty& GetWindowProperty() const = 0; + virtual bool IsVSyncEnable() const = 0; + virtual void SetVSync(bool value) = 0; + virtual void SetCallbackFunction(const EventCallbackFn& callback) = 0; + virtual const WindowProperty& GetWindowProperty() const = 0; - virtual bool CreateSurface(void* instance, void** out_window_surface) = 0; - virtual std::vector GetRequiredExtensionLayers() = 0; - virtual void* GetNativeWindow() const = 0; + virtual bool CreateSurface(void* instance, void** out_window_surface) = 0; + virtual std::vector GetRequiredExtensionLayers() = 0; + virtual void* GetNativeWindow() const = 0; - virtual std::future OpenFileDialogAsync(std::span type_filters = {}) = 0; + virtual std::future OpenFileDialogAsync(std::span type_filters = {}) = 0; - virtual void PollEvent() = 0; - virtual float GetTime() = 0; - virtual float GetDeltaTime() = 0; + virtual void PollEvent() = 0; + virtual float GetTime() = 0; + virtual float GetDeltaTime() = 0; - virtual void ForwardEventToLayers(Core::CoreEvent& event); + virtual void ForwardEventToLayers(Core::CoreEvent& event); - virtual void Deinitialize() {} + virtual void Deinitialize() {} protected: Core::TimeStep m_delta_time; diff --git a/ZEngine/ZEngine/Windows/Layers/LayerStack.h b/ZEngine/ZEngine/Windows/Layers/LayerStack.h index 6f724f73..6d01208d 100644 --- a/ZEngine/ZEngine/Windows/Layers/LayerStack.h +++ b/ZEngine/ZEngine/Windows/Layers/LayerStack.h @@ -1,6 +1,6 @@ // #pragma once // #include -// #include +// #include // #include // // namespace ZEngine::Windows::Layers @@ -10,7 +10,7 @@ // struct LayerStack // { // template -// using Array = Core::Container::Array; +// using Array = Core::Containers::Array; // // LayerStack() = default; // ~LayerStack(); diff --git a/ZEngine/ZEngine/Windows/WindowConfiguration.h b/ZEngine/ZEngine/Windows/WindowConfiguration.h index a943e66b..f762d6d3 100644 --- a/ZEngine/ZEngine/Windows/WindowConfiguration.h +++ b/ZEngine/ZEngine/Windows/WindowConfiguration.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include #include namespace ZEngine::Windows::Layers @@ -12,13 +12,13 @@ namespace ZEngine::Windows { struct WindowConfiguration { - uint32_t Width = 1500; - uint32_t Height = 800; - bool EnableVsync = true; - Core::Container::String Title; + uint32_t Width = 1500; + uint32_t Height = 800; + bool EnableVsync = true; + Core::Containers::String Title; - Core::Container::Array RenderingLayerCollection; - Core::Container::Array OverlayLayerCollection; + Core::Containers::Array RenderingLayerCollection; + Core::Containers::Array OverlayLayerCollection; }; } // namespace ZEngine::Windows diff --git a/ZEngine/ZEngine/Windows/WindowProperty.h b/ZEngine/ZEngine/Windows/WindowProperty.h index e9848779..18968dbd 100644 --- a/ZEngine/ZEngine/Windows/WindowProperty.h +++ b/ZEngine/ZEngine/Windows/WindowProperty.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include namespace ZEngine::Windows diff --git a/ZEngine/ZEngine/ZEngineDef.h b/ZEngine/ZEngine/ZEngineDef.h index 674f81ff..6e1cf1f5 100644 --- a/ZEngine/ZEngine/ZEngineDef.h +++ b/ZEngine/ZEngine/ZEngineDef.h @@ -67,6 +67,6 @@ #endif #define ZPushDynamicArray(pool, type) ((type*) (pool)->Allocate(__FILE__, __LINE__)) - +#define ZAlloc(allocator, size, alignment) ((allocator)->Allocate((size), (alignment))) #define ZResize(allocator, ptr, old_size, new_size, alignment) ((allocator)->Resize((ptr), (old_size), (new_size), (alignment))) #define ZAlignof(type) ((alignof(type) < DEFAULT_ALIGNMENT) ? DEFAULT_ALIGNMENT : alignof(type)) diff --git a/ZEngine/tests/CMakeLists.txt b/ZEngine/tests/CMakeLists.txt index 3edccce3..bfb19767 100644 --- a/ZEngine/tests/CMakeLists.txt +++ b/ZEngine/tests/CMakeLists.txt @@ -8,6 +8,7 @@ set (TEST_SOURCES allocator_test.cpp array_test.cpp string_test.cpp + hashmap_test.cpp ) add_executable(ZEngineTests ${TEST_SOURCES}) diff --git a/ZEngine/tests/array_test.cpp b/ZEngine/tests/array_test.cpp index ecd1c779..2bbd483e 100644 --- a/ZEngine/tests/array_test.cpp +++ b/ZEngine/tests/array_test.cpp @@ -1,7 +1,7 @@ -#include +#include #include -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; using namespace ZEngine::Core::Memory; class ArrayTest : public ::testing::Test diff --git a/ZEngine/tests/hashmap_test.cpp b/ZEngine/tests/hashmap_test.cpp new file mode 100644 index 00000000..4b3e6835 --- /dev/null +++ b/ZEngine/tests/hashmap_test.cpp @@ -0,0 +1,151 @@ +#include +#include +#include + +using namespace ZEngine::Core::Containers; +using namespace ZEngine::Core::Memory; + +class HashMapTest : public ::testing::Test +{ +protected: + void SetUp() override + { + allocator.Initialize(2000); + } + void TearDown() override + { + allocator.Shutdown(); + } + ArenaAllocator allocator; +}; + +TEST_F(HashMapTest, InitialState) +{ + HashMap array; + array.init(&allocator, 10, 0); + EXPECT_EQ(array.size(), 0); + EXPECT_EQ(array.capacity(), 10); + EXPECT_TRUE(array.empty()); +} + +TEST_F(HashMapTest, Contains) +{ + HashMap map; + map.init(&allocator, 10, 0); + map.insert(1, 10); + EXPECT_TRUE(map.contains(1)); + EXPECT_FALSE(map.contains(2)); +} + +TEST_F(HashMapTest, BracketOperator) +{ + HashMap map; + map.init(&allocator, 10, 0); + map[1] = 10; + EXPECT_EQ(map[1], 10); + + map[1] = 20; + EXPECT_EQ(map[1], 20); + + EXPECT_EQ(map[2], 0); + EXPECT_TRUE(map.contains(2)); +} + +TEST_F(HashMapTest, Remove) +{ + HashMap map; + map.init(&allocator, 10, 0); + map.insert(1, 10); + map.insert(2, 20); + EXPECT_EQ(map.size(), 2); + map.remove(1); + EXPECT_EQ(map.size(), 1); + EXPECT_FALSE(map.contains(1)); + EXPECT_TRUE(map.contains(2)); +} + +TEST_F(HashMapTest, Find) +{ + HashMap map; + map.init(&allocator, 10, 0); + map.insert(1, 10); + int* value = map.find(1); + ASSERT_NE(value, nullptr); + EXPECT_EQ(*value, 10); + int* non_existent = map.find(2); + EXPECT_EQ(non_existent, nullptr); +} + +TEST_F(HashMapTest, Clear) +{ + HashMap map; + map.init(&allocator, 10, 0); + + // Insert multiple elements + map.insert(1, 10); + map.insert(2, 20); + map.insert(3, 30); + + EXPECT_EQ(map.size(), 3); + + map.clear(); + + EXPECT_EQ(map.size(), 0); + EXPECT_TRUE(map.empty()); + + EXPECT_FALSE(map.contains(1)); + EXPECT_FALSE(map.contains(2)); + EXPECT_FALSE(map.contains(3)); +} + +TEST_F(HashMapTest, Resize) +{ + HashMap map; + map.init(&allocator, 2, 0); + + for (int i = 0; i < 10; ++i) { + map.insert(i, i * 10); + } + + EXPECT_EQ(map.size(), 10); + + + + for (int i = 0; i < 10; ++i) { + EXPECT_TRUE(map.contains(i)); + auto x = map[i]; + EXPECT_EQ(map[i], i * 10); + } + + EXPECT_GT(map.capacity(), 2); +} + +TEST_F(HashMapTest, OverwriteValue) +{ + HashMap map; + map.init(&allocator, 10, 0); + + map.insert(1, 10); + EXPECT_EQ(map[1], 10); + + map.insert(1, 20); + EXPECT_EQ(map[1], 20); +} + +TEST_F(HashMapTest, CollisionHandling) +{ + HashMap map; + map.init(&allocator, 2, 0); + + map.insert(1, 10); + map.insert(3, 30); + map.insert(5, 50); + + EXPECT_TRUE(map.contains(1)); + EXPECT_TRUE(map.contains(3)); + EXPECT_TRUE(map.contains(5)); + + EXPECT_EQ(map[1], 10); + EXPECT_EQ(map[3], 30); + EXPECT_EQ(map[5], 50); +} \ No newline at end of file diff --git a/ZEngine/tests/string_test.cpp b/ZEngine/tests/string_test.cpp index 42a73544..a366e896 100644 --- a/ZEngine/tests/string_test.cpp +++ b/ZEngine/tests/string_test.cpp @@ -1,7 +1,7 @@ -#include +#include #include -using namespace ZEngine::Core::Container; +using namespace ZEngine::Core::Containers; using namespace ZEngine::Core::Memory; class StringTest : public ::testing::Test diff --git a/__externals/externals.cmake b/__externals/externals.cmake index f611bcbb..35f6d663 100644 --- a/__externals/externals.cmake +++ b/__externals/externals.cmake @@ -6,6 +6,7 @@ set(EXTERNAL_INCLUDE_DIRS ${EXTERNAL_DIR}/glm/glm ${EXTERNAL_DIR}/imgui/src ${EXTERNAL_DIR}/tlsf/src + ${EXTERNAL_DIR}/rapidhash/src ${EXTERNAL_DIR}/spdlog/include ${EXTERNAL_DIR}/glfw/include ${EXTERNAL_DIR}/entt @@ -55,4 +56,5 @@ target_link_libraries(imported::External_libs INTERFACE glslang SPIRV SPIRV-Tools tlsf + rapidhash ) diff --git a/__externals/rapidhash/CMakeLists.txt b/__externals/rapidhash/CMakeLists.txt new file mode 100644 index 00000000..44218ca0 --- /dev/null +++ b/__externals/rapidhash/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.12) +project(rapidhash) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_library(rapidhash INTERFACE) + +target_include_directories(rapidhash INTERFACE + $ +) diff --git a/__externals/rapidhash/src b/__externals/rapidhash/src new file mode 160000 index 00000000..c1f35e3a --- /dev/null +++ b/__externals/rapidhash/src @@ -0,0 +1 @@ +Subproject commit c1f35e3a44010bf90a9008013d8ab7c7b9aaae2c From 4d5ca6d2379fdaaec54ea4cf13cffafd7e70dbb0 Mon Sep 17 00:00:00 2001 From: jnyfah Date: Tue, 25 Mar 2025 22:23:45 +0100 Subject: [PATCH 2/9] because format is my worst enemy --- ZEngine/ZEngine/Core/Containers/HashMap.h | 12 ++----- ZEngine/tests/hashmap_test.cpp | 43 +++++++++++------------ 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/ZEngine/ZEngine/Core/Containers/HashMap.h b/ZEngine/ZEngine/Core/Containers/HashMap.h index 9bffa670..1262f817 100644 --- a/ZEngine/ZEngine/Core/Containers/HashMap.h +++ b/ZEngine/ZEngine/Core/Containers/HashMap.h @@ -83,7 +83,7 @@ namespace ZEngine::Core::Containers if (m_size >= m_capacity * 0.75) { reserve(m_capacity ? m_capacity * 2 : 8); - index = hash(key); // Recompute after reserve + index = hash(key); } Node* new_node = static_cast(ZAlloc(m_allocator, sizeof(Node), ZAlignof(Node))); @@ -147,13 +147,7 @@ namespace ZEngine::Core::Containers { for (size_t i = 0; i < m_capacity; ++i) { - Node* current = m_data[i].head; - while (current) - { - Node* next = current->next; - // Optionally free current node here - current = next; - } + Node* current = m_data[i].head; m_data[i].head = nullptr; } m_size = 0; @@ -176,7 +170,7 @@ namespace ZEngine::Core::Containers { Node* next = current->next; - size_t new_index = hash(current->key); // Now uses new m_capacity + size_t new_index = hash(current->key); current->next = m_data[new_index].head; m_data[new_index].head = current; diff --git a/ZEngine/tests/hashmap_test.cpp b/ZEngine/tests/hashmap_test.cpp index 4b3e6835..13248281 100644 --- a/ZEngine/tests/hashmap_test.cpp +++ b/ZEngine/tests/hashmap_test.cpp @@ -10,7 +10,7 @@ class HashMapTest : public ::testing::Test protected: void SetUp() override { - allocator.Initialize(2000); + allocator.Initialize(2000); } void TearDown() override { @@ -37,16 +37,16 @@ TEST_F(HashMapTest, Contains) EXPECT_FALSE(map.contains(2)); } -TEST_F(HashMapTest, BracketOperator) +TEST_F(HashMapTest, BracketOperator) { HashMap map; map.init(&allocator, 10, 0); map[1] = 10; EXPECT_EQ(map[1], 10); - + map[1] = 20; EXPECT_EQ(map[1], 20); - + EXPECT_EQ(map[2], 0); EXPECT_TRUE(map.contains(2)); } @@ -80,19 +80,19 @@ TEST_F(HashMapTest, Clear) { HashMap map; map.init(&allocator, 10, 0); - + // Insert multiple elements map.insert(1, 10); map.insert(2, 20); map.insert(3, 30); - + EXPECT_EQ(map.size(), 3); map.clear(); - + EXPECT_EQ(map.size(), 0); EXPECT_TRUE(map.empty()); - + EXPECT_FALSE(map.contains(1)); EXPECT_FALSE(map.contains(2)); EXPECT_FALSE(map.contains(3)); @@ -101,33 +101,32 @@ TEST_F(HashMapTest, Clear) TEST_F(HashMapTest, Resize) { HashMap map; - map.init(&allocator, 2, 0); + map.init(&allocator, 2, 0); - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < 10; ++i) + { map.insert(i, i * 10); } EXPECT_EQ(map.size(), 10); - - - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < 10; ++i) + { EXPECT_TRUE(map.contains(i)); - auto x = map[i]; EXPECT_EQ(map[i], i * 10); } - - EXPECT_GT(map.capacity(), 2); + + EXPECT_GT(map.capacity(), 2); } TEST_F(HashMapTest, OverwriteValue) { HashMap map; map.init(&allocator, 10, 0); - + map.insert(1, 10); EXPECT_EQ(map[1], 10); - + map.insert(1, 20); EXPECT_EQ(map[1], 20); } @@ -136,15 +135,15 @@ TEST_F(HashMapTest, CollisionHandling) { HashMap map; map.init(&allocator, 2, 0); - + map.insert(1, 10); map.insert(3, 30); - map.insert(5, 50); - + map.insert(5, 50); + EXPECT_TRUE(map.contains(1)); EXPECT_TRUE(map.contains(3)); EXPECT_TRUE(map.contains(5)); - + EXPECT_EQ(map[1], 10); EXPECT_EQ(map[3], 30); EXPECT_EQ(map[5], 50); From 91ccce710b66cf4575ea6a24794a2ce193783c4d Mon Sep 17 00:00:00 2001 From: jnyfah Date: Tue, 25 Mar 2025 23:27:53 +0100 Subject: [PATCH 3/9] removing size from array initialization because i dont see the point of it --- Tetragrama/Editor.cpp | 12 ++++++------ Tetragrama/Layers/ImguiLayer.cpp | 10 +++++----- ZEngine/ZEngine/Core/Containers/Array.h | 4 ++-- ZEngine/tests/array_test.cpp | 14 +++++++------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Tetragrama/Editor.cpp b/Tetragrama/Editor.cpp index e3b71764..b8aa4b60 100644 --- a/Tetragrama/Editor.cpp +++ b/Tetragrama/Editor.cpp @@ -49,8 +49,8 @@ namespace Tetragrama std::string title = fmt::format("{0} - Active Scene : {1}", Context->ConfigurationPtr->ProjectName, Context->CurrentScenePtr->Name); Windows::WindowConfiguration window_conf = {.EnableVsync = true}; window_conf.Title.init(&(Context->Arena), title.c_str()); - window_conf.RenderingLayerCollection.init(&(Context->Arena), 1, 0); - window_conf.OverlayLayerCollection.init(&(Context->Arena), 1, 0); + window_conf.RenderingLayerCollection.init(&(Context->Arena), 1); + window_conf.OverlayLayerCollection.init(&(Context->Arena), 1); window_conf.RenderingLayerCollection.push(CanvasLayer); window_conf.OverlayLayerCollection.push(UILayer); @@ -74,10 +74,10 @@ namespace Tetragrama RenderScene = ZPushStructCtor(arena, ZEngine::Rendering::Scenes::GraphicScene); RenderScene->IsDrawDataDirty = true; - MeshFiles.init(arena, 1, 0); - ModelFiles.init(arena, 1, 0); - MaterialFiles.init(arena, 1, 0); - Hashes.init(arena, 1, 0); + MeshFiles.init(arena, 1); + ModelFiles.init(arena, 1); + MaterialFiles.init(arena, 1); + Hashes.init(arena, 1); } void EditorScene::Push(ZEngine::Core::Memory::ArenaAllocator* arena, const char* mesh, const char* model, const char* material) diff --git a/Tetragrama/Layers/ImguiLayer.cpp b/Tetragrama/Layers/ImguiLayer.cpp index 30158f9c..35a65237 100644 --- a/Tetragrama/Layers/ImguiLayer.cpp +++ b/Tetragrama/Layers/ImguiLayer.cpp @@ -29,7 +29,7 @@ namespace Tetragrama::Layers { arena->CreateSubArena(ZMega(5), &LayerArena); - NodeHierarchies.init(&LayerArena, 10, 0); + NodeHierarchies.init(&LayerArena, 10); auto dockspace_cmp = ZPushStructCtor(&LayerArena, Components::DockspaceUIComponent); auto scene_cmp = ZPushStructCtor(&LayerArena, Components::SceneViewportUIComponent); @@ -48,7 +48,7 @@ namespace Tetragrama::Layers hierarchy_view_cmp->Initialize(this); demo_cmp->Initialize(this); - dockspace_cmp->Children.init(&LayerArena, 8, 7); + dockspace_cmp->Children.init(&LayerArena, 8); dockspace_cmp->Children.push(scene_cmp); dockspace_cmp->Children.push(editor_log_cmp); dockspace_cmp->Children.push(demo_cmp); @@ -121,9 +121,9 @@ namespace Tetragrama::Layers Array children = {}; Array siblings = {}; - roots.init(temp_arena.Arena, 1, 0); - children.init(temp_arena.Arena, 1, 0); - siblings.init(temp_arena.Arena, 1, 0); + roots.init(temp_arena.Arena, 1); + children.init(temp_arena.Arena, 1); + siblings.init(temp_arena.Arena, 1); uint32_t i = 0; for (auto& node : NodeHierarchies) diff --git a/ZEngine/ZEngine/Core/Containers/Array.h b/ZEngine/ZEngine/Core/Containers/Array.h index e6630f4e..3236341e 100644 --- a/ZEngine/ZEngine/Core/Containers/Array.h +++ b/ZEngine/ZEngine/Core/Containers/Array.h @@ -21,10 +21,10 @@ namespace ZEngine::Core::Containers using iterator = T*; using const_iterator = const T*; - void init(Memory::ArenaAllocator* allocator, size_type initial_capacity, size_type initial_size = 0U) + void init(Memory::ArenaAllocator* allocator, size_type initial_capacity) { m_allocator = allocator; - m_size = initial_size; + m_size = 0; m_capacity = 0; m_data = nullptr; reserve(initial_capacity); diff --git a/ZEngine/tests/array_test.cpp b/ZEngine/tests/array_test.cpp index 2bbd483e..de805bd1 100644 --- a/ZEngine/tests/array_test.cpp +++ b/ZEngine/tests/array_test.cpp @@ -23,7 +23,7 @@ class ArrayTest : public ::testing::Test TEST_F(ArrayTest, InitialState) { Array array; - array.init(&allocator, 10, 0); + array.init(&allocator, 10); EXPECT_EQ(array.size(), 0); EXPECT_EQ(array.capacity(), 10); @@ -33,7 +33,7 @@ TEST_F(ArrayTest, InitialState) TEST_F(ArrayTest, PushBack) { Array array; - array.init(&allocator, 4, 0); + array.init(&allocator, 4); array.push(1); array.push(2); @@ -49,7 +49,7 @@ TEST_F(ArrayTest, PushBack) TEST_F(ArrayTest, AutoResize) { Array array; - array.init(&allocator, 2, 0); + array.init(&allocator, 2); EXPECT_EQ(array.capacity(), 2); @@ -65,7 +65,7 @@ TEST_F(ArrayTest, AutoResize) TEST_F(ArrayTest, PopBack) { Array array; - array.init(&allocator, 4, 0); + array.init(&allocator, 4); array.push(1); array.push(2); @@ -87,7 +87,7 @@ TEST_F(ArrayTest, PopBack) TEST_F(ArrayTest, Clear) { Array array; - array.init(&allocator, 4, 0); + array.init(&allocator, 4); array.push(1); array.push(2); @@ -105,7 +105,7 @@ TEST_F(ArrayTest, Clear) TEST_F(ArrayTest, Reserve) { Array array; - array.init(&allocator, 4, 0); + array.init(&allocator, 4); EXPECT_EQ(array.capacity(), 4); @@ -119,7 +119,7 @@ TEST_F(ArrayTest, Reserve) TEST_F(ArrayTest, FrontAndBack) { Array array; - array.init(&allocator, 4, 0); + array.init(&allocator, 4); array.push(10); EXPECT_EQ(array.front(), 10); From 9482295dee55206353a9f0e59ba3e9c7be44e9ca Mon Sep 17 00:00:00 2001 From: jnyfah Date: Wed, 26 Mar 2025 00:20:02 +0100 Subject: [PATCH 4/9] adding some string to hashmap test because why not --- ZEngine/ZEngine/Core/Containers/HashMap.h | 1 - ZEngine/tests/hashmap_test.cpp | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ZEngine/ZEngine/Core/Containers/HashMap.h b/ZEngine/ZEngine/Core/Containers/HashMap.h index 1262f817..48ace98b 100644 --- a/ZEngine/ZEngine/Core/Containers/HashMap.h +++ b/ZEngine/ZEngine/Core/Containers/HashMap.h @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include diff --git a/ZEngine/tests/hashmap_test.cpp b/ZEngine/tests/hashmap_test.cpp index 13248281..83966f34 100644 --- a/ZEngine/tests/hashmap_test.cpp +++ b/ZEngine/tests/hashmap_test.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -121,14 +122,20 @@ TEST_F(HashMapTest, Resize) TEST_F(HashMapTest, OverwriteValue) { - HashMap map; + HashMap map; map.init(&allocator, 10, 0); - map.insert(1, 10); - EXPECT_EQ(map[1], 10); + String str1; + str1.init(&allocator, "first"); - map.insert(1, 20); - EXPECT_EQ(map[1], 20); + String str2; + str2.init(&allocator, "updated"); + + map.insert(1, str1); + EXPECT_STREQ(map[1].c_str(), str1.c_str()); + + map.insert(1, str2); + EXPECT_STREQ(map[1].c_str(), str2.c_str()); } TEST_F(HashMapTest, CollisionHandling) From a81e6068edf5bf6b1eb5a79e863955096dab834c Mon Sep 17 00:00:00 2001 From: jnyfah Date: Thu, 27 Mar 2025 14:23:52 +0100 Subject: [PATCH 5/9] added initializer list and some tests for arrayview --- ZEngine/ZEngine/Core/Containers/Array.h | 2 - .../ZEngine/Core/Containers/InitializerList.h | 73 ++++++++++++++++ ZEngine/tests/CMakeLists.txt | 1 + ZEngine/tests/array_test.cpp | 19 +++++ ZEngine/tests/initializerlist_test.cpp | 84 +++++++++++++++++++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 ZEngine/ZEngine/Core/Containers/InitializerList.h create mode 100644 ZEngine/tests/initializerlist_test.cpp diff --git a/ZEngine/ZEngine/Core/Containers/Array.h b/ZEngine/ZEngine/Core/Containers/Array.h index 3236341e..8a442064 100644 --- a/ZEngine/ZEngine/Core/Containers/Array.h +++ b/ZEngine/ZEngine/Core/Containers/Array.h @@ -2,8 +2,6 @@ #include #include -// using span ? - using namespace ZEngine::Core::Memory; namespace ZEngine::Core::Containers diff --git a/ZEngine/ZEngine/Core/Containers/InitializerList.h b/ZEngine/ZEngine/Core/Containers/InitializerList.h new file mode 100644 index 00000000..71ef4b12 --- /dev/null +++ b/ZEngine/ZEngine/Core/Containers/InitializerList.h @@ -0,0 +1,73 @@ +#pragma once +#include + +using namespace ZEngine::Core::Memory; + +namespace ZEngine::Core::Containers +{ + + template + struct InitializerList + { + using value_type = T; + using size_type = size_t; + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using const_iterator = const T*; + using pointer = T*; + using const_pointer = const T*; + + InitializerList(pointer data, size_type size) : m_data(data), m_size(size) {} + + iterator begin() + { + return m_data; + } + + const_iterator begin() const + { + return m_data; + } + + iterator end() + { + return m_data + m_size; + } + + const_iterator end() const + { + return m_data + m_size; + } + + pointer data() + { + return m_data; + } + + const_pointer data() const + { + return m_data; + } + + bool empty() const + { + return m_size == 0; + } + + size_type size() const + { + return m_size; + } + + size_type m_size; + pointer m_data; + }; + + template + InitializerList make_initializer_list(T (&arr)[N]) + { + return InitializerList(arr, N); + } + +} // namespace ZEngine::Core::Containers \ No newline at end of file diff --git a/ZEngine/tests/CMakeLists.txt b/ZEngine/tests/CMakeLists.txt index bfb19767..042304b7 100644 --- a/ZEngine/tests/CMakeLists.txt +++ b/ZEngine/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set (TEST_SOURCES array_test.cpp string_test.cpp hashmap_test.cpp + initializerlist_test.cpp ) add_executable(ZEngineTests ${TEST_SOURCES}) diff --git a/ZEngine/tests/array_test.cpp b/ZEngine/tests/array_test.cpp index de805bd1..6bab1ef3 100644 --- a/ZEngine/tests/array_test.cpp +++ b/ZEngine/tests/array_test.cpp @@ -130,4 +130,23 @@ TEST_F(ArrayTest, FrontAndBack) EXPECT_EQ(array.front(), 10); EXPECT_EQ(array.back(), 30); +} + +TEST_F(ArrayTest, ArrayViewWrap) +{ + Array array; + array.init(&allocator, 4); + array.push(10); + array.push(20); + array.push(30); + + ArrayView view(array); + + EXPECT_EQ(view.size(), array.size()); + EXPECT_EQ(view[0], 10); + EXPECT_EQ(view[1], 20); + EXPECT_EQ(view[2], 30); + + view[1] = 99; + EXPECT_EQ(array[1], 99); } \ No newline at end of file diff --git a/ZEngine/tests/initializerlist_test.cpp b/ZEngine/tests/initializerlist_test.cpp new file mode 100644 index 00000000..53435f2d --- /dev/null +++ b/ZEngine/tests/initializerlist_test.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +using namespace ZEngine::Core::Containers; +using namespace ZEngine::Core::Memory; + +class InitializerListTest : public ::testing::Test +{ +protected: + void SetUp() override + { + arena.Initialize(512); + } + + void TearDown() override + { + arena.Shutdown(); + } + + ArenaAllocator arena; +}; + +TEST_F(InitializerListTest, WithArray) +{ + Array array; + array.init(&arena, 4); + array.push(1); + array.push(2); + array.push(3); + array.push(4); + + InitializerList list(array.data(), array.size()); + + EXPECT_EQ(list.size(), 4); + EXPECT_EQ(list.data()[0], 1); + EXPECT_EQ(*(list.begin() + 2), 3); + + int total = 0; + for (int val : list) + { + total += val; + } + + EXPECT_EQ(total, 10); +} + +TEST_F(InitializerListTest, WithStrings) +{ + Array str_array; + str_array.init(&arena, 3); + str_array.push(String()); + str_array.push(String()); + str_array.push(String()); + + str_array[0].init(&arena, "Alpha"); + str_array[1].init(&arena, "Beta"); + str_array[2].init(&arena, "Gamma"); + + InitializerList list(str_array.data(), str_array.size()); + + EXPECT_EQ(list.size(), 3); + EXPECT_STREQ(list.data()[0].c_str(), "Alpha"); + EXPECT_STREQ(list.data()[2].c_str(), "Gamma"); + + std::string result; + for (const auto& str : list) + result += str.c_str(); + + EXPECT_EQ(result, "AlphaBetaGamma"); +} + +TEST_F(InitializerListTest, EmptyFromArray) +{ + Array empty_array; + empty_array.init(&arena, 0); + + InitializerList list(empty_array.data(), empty_array.size()); + + EXPECT_EQ(list.size(), 0); + EXPECT_TRUE(list.empty()); + EXPECT_EQ(list.begin(), list.end()); +} From 30fe3f6ecb4f2d283ce55fc77e510b960cc28d2a Mon Sep 17 00:00:00 2001 From: jnyfah Date: Sun, 30 Mar 2025 21:14:11 +0100 Subject: [PATCH 6/9] some changes --- ZEngine/ZEngine/Core/Containers/HashMap.h | 81 +++++++++++++++- ZEngine/ZEngine/Core/Containers/Strings.h | 32 +++++++ ZEngine/ZEngine/Helpers/MemoryOperations.h | 20 ++++ ZEngine/tests/hashmap_test.cpp | 106 +++++++++++++++++++++ 4 files changed, 238 insertions(+), 1 deletion(-) diff --git a/ZEngine/ZEngine/Core/Containers/HashMap.h b/ZEngine/ZEngine/Core/Containers/HashMap.h index 48ace98b..53892ca5 100644 --- a/ZEngine/ZEngine/Core/Containers/HashMap.h +++ b/ZEngine/ZEngine/Core/Containers/HashMap.h @@ -200,6 +200,85 @@ namespace ZEngine::Core::Containers size_t m_size = 0; size_t m_capacity = 0; KeyValue* m_data = nullptr; + + struct HashMapView + { + struct Iterator + { + using KeyValuePair = std::pair; + + Iterator(HashMap* map, size_t index, Node* node) : m_map(map), m_index(index), m_current_node(node) {} + + KeyValuePair operator*() const + { + return KeyValuePair(m_current_node->key, m_current_node->value); + } + + Iterator& operator++() + { + if (m_current_node->next) + { + m_current_node = m_current_node->next; + } + else + { + m_current_node = nullptr; + m_index++; + + while (m_index < m_map->m_capacity) + { + if (m_map->m_data[m_index].head) + { + m_current_node = m_map->m_data[m_index].head; + break; + } + m_index++; + } + } + return *this; + } + + bool operator!=(const Iterator& other) const + { + return m_current_node != other.m_current_node; + } + + bool operator==(const Iterator& other) const + { + return m_current_node == other.m_current_node; + } + + HashMap* m_map; + size_t m_index; + Node* m_current_node; + }; + + HashMapView(HashMap* map) : m_map(map) {} + + Iterator begin() + { + for (size_t i = 0; i < m_map->m_capacity; ++i) + { + if (m_map->m_data[i].head) + { + return Iterator(m_map, i, m_map->m_data[i].head); + } + } + return end(); + } + + Iterator end() + { + return Iterator(m_map, m_map->m_capacity, nullptr); + } + + HashMap* m_map; + }; + + HashMapView view() + { + return HashMapView(this); + } }; -} // namespace ZEngine::Core::Containers +} // namespace ZEngine::Core::Containers \ No newline at end of file diff --git a/ZEngine/ZEngine/Core/Containers/Strings.h b/ZEngine/ZEngine/Core/Containers/Strings.h index 984a914c..e4b13a65 100644 --- a/ZEngine/ZEngine/Core/Containers/Strings.h +++ b/ZEngine/ZEngine/Core/Containers/Strings.h @@ -103,6 +103,38 @@ namespace ZEngine::Core::Containers return m_data[index]; } + bool operator==(const String& other) const + { + if (m_size != other.m_size) + return false; + return Helpers::secure_strcmp(m_data, other.m_data) == 0; + } + + bool operator!=(const String& other) const + { + return !(*this == other); + } + + bool operator<(const String& other) const + { + return Helpers::secure_strcmp(m_data, other.m_data) < 0; + } + + bool operator>(const String& other) const + { + return Helpers::secure_strcmp(m_data, other.m_data) > 0; + } + + bool operator<=(const String& other) const + { + return !(*this > other); + } + + bool operator>=(const String& other) const + { + return !(*this < other); + } + iterator begin() { return m_data; diff --git a/ZEngine/ZEngine/Helpers/MemoryOperations.h b/ZEngine/ZEngine/Helpers/MemoryOperations.h index a261d717..235d17f1 100644 --- a/ZEngine/ZEngine/Helpers/MemoryOperations.h +++ b/ZEngine/ZEngine/Helpers/MemoryOperations.h @@ -123,6 +123,26 @@ namespace ZEngine::Helpers #endif } + inline int secure_strcmp(const char* str1, const char* str2) + { + if (!str1 || !str2) + { + return MEMORY_OP_FAILURE; + } + +#if SECURE_C11_FUNCTIONS_AVAILABLE + // There is no secure C11 version of strcmp, so we fall back to manual comparison +#endif + + while (*str1 && (*str1 == *str2)) + { + ++str1; + ++str2; + } + + return static_cast(*str1) - static_cast(*str2); + } + inline int secure_memcmp(const void* ptr1, size_t ptr1Size, const void* ptr2, size_t ptr2Size, size_t num) { if (!ptr1 || !ptr2) diff --git a/ZEngine/tests/hashmap_test.cpp b/ZEngine/tests/hashmap_test.cpp index 83966f34..580cdac8 100644 --- a/ZEngine/tests/hashmap_test.cpp +++ b/ZEngine/tests/hashmap_test.cpp @@ -154,4 +154,110 @@ TEST_F(HashMapTest, CollisionHandling) EXPECT_EQ(map[1], 10); EXPECT_EQ(map[3], 30); EXPECT_EQ(map[5], 50); +} + +TEST_F(HashMapTest, ViewIteration) +{ + HashMap map; + map.init(&allocator, 8, 0); + + map.insert(10, 100); + map.insert(20, 200); + map.insert(30, 300); + + std::unordered_map expected = { + {10, 100}, + {20, 200}, + {30, 300} + }; + + auto view = map.view(); + for (auto [key, value] : view) + { + auto it = expected.find(key); + ASSERT_NE(it, expected.end()); + EXPECT_EQ(value, it->second); + expected.erase(it); + } + + EXPECT_TRUE(expected.empty()); +} + +TEST_F(HashMapTest, UserDefinedStructViewIterations) +{ + struct Person + { + String name; + int age; + + bool operator==(const Person& other) const + { + return name == other.name && age == other.age; + } + }; + + HashMap map; + map.init(&allocator, 8, 0); + + String str1; + str1.init(&allocator, "Alice"); + String str2; + str2.init(&allocator, "Bob"); + String str3; + str3.init(&allocator, "Carol"); + String str4; + str4.init(&allocator, "Engineer"); + String str5; + str5.init(&allocator, "Designer"); + String str6; + str6.init(&allocator, "Artist"); + + Person alice{str1, 30}; + Person bob{str2, 25}; + Person carol{str3, 28}; + + map.insert(alice, str4); + map.insert(bob, str5); + map.insert(carol, str6); + + EXPECT_TRUE(map.contains(alice)); + EXPECT_TRUE(map.contains(bob)); + + EXPECT_EQ(map[alice], str4); + EXPECT_EQ(map[bob], str5); + + struct ExpectedEntry + { + Person key; + String value; + bool matched = false; + }; + + ExpectedEntry expected[] = { + {alice, str4}, + { bob, str5}, + {carol, str6} + }; + + size_t matched_count = 0; + + auto view = map.view(); + for (auto [key, value] : view) + { + bool found = false; + for (auto& entry : expected) + { + if (!entry.matched && entry.key == key) + { + EXPECT_EQ(value, entry.value); + entry.matched = true; + found = true; + matched_count++; + break; + } + } + ASSERT_TRUE(found); + } + + EXPECT_EQ(matched_count, 3); } \ No newline at end of file From 226d8302c74ed8383cf9ce2063ca8c8786543b90 Mon Sep 17 00:00:00 2001 From: jnyfah Date: Sun, 30 Mar 2025 22:56:16 +0100 Subject: [PATCH 7/9] make lists?? --- ZEngine/ZEngine/Core/Containers/Array.h | 14 +++++++++++ .../ZEngine/Core/Containers/InitializerList.h | 15 +++++++++--- ZEngine/tests/array_test.cpp | 23 ++++--------------- ZEngine/tests/initializerlist_test.cpp | 10 ++------ 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/ZEngine/ZEngine/Core/Containers/Array.h b/ZEngine/ZEngine/Core/Containers/Array.h index 8a442064..ed081616 100644 --- a/ZEngine/ZEngine/Core/Containers/Array.h +++ b/ZEngine/ZEngine/Core/Containers/Array.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include + using namespace ZEngine::Core::Memory; namespace ZEngine::Core::Containers @@ -28,6 +30,18 @@ namespace ZEngine::Core::Containers reserve(initial_capacity); } + void init(Memory::ArenaAllocator* allocator, size_type initial_capacity, const InitializerList& list) + { + // Initialize the basic array structure + init(allocator, std::max(initial_capacity, list.size())); + + // Add all elements from the initializer list + for (const auto& item : list) + { + push(item); + } + } + const_reference operator[](size_type index) const { ZENGINE_VALIDATE_ASSERT(index < m_size, "Index out of range") diff --git a/ZEngine/ZEngine/Core/Containers/InitializerList.h b/ZEngine/ZEngine/Core/Containers/InitializerList.h index 71ef4b12..18ec23a5 100644 --- a/ZEngine/ZEngine/Core/Containers/InitializerList.h +++ b/ZEngine/ZEngine/Core/Containers/InitializerList.h @@ -64,10 +64,19 @@ namespace ZEngine::Core::Containers pointer m_data; }; - template - InitializerList make_initializer_list(T (&arr)[N]) + template + InitializerList make_initializer_list(Memory::ArenaAllocator* allocator, T first, Args... args) { - return InitializerList(arr, N); + size_t count = sizeof...(args) + 1; + + T* buffer = static_cast(ZAlloc(allocator, count * sizeof(T), ZAlignof(T))); + + buffer[0] = first; + + size_t i = 1; + ((buffer[i++] = static_cast(args)), ...); + + return InitializerList(buffer, count); } } // namespace ZEngine::Core::Containers \ No newline at end of file diff --git a/ZEngine/tests/array_test.cpp b/ZEngine/tests/array_test.cpp index 6bab1ef3..880795c6 100644 --- a/ZEngine/tests/array_test.cpp +++ b/ZEngine/tests/array_test.cpp @@ -33,11 +33,7 @@ TEST_F(ArrayTest, InitialState) TEST_F(ArrayTest, PushBack) { Array array; - array.init(&allocator, 4); - - array.push(1); - array.push(2); - array.push(3); + array.init(&allocator, 4, make_initializer_list(&allocator, 1, 2, 3)); EXPECT_EQ(array.size(), 3); EXPECT_FALSE(array.empty()); @@ -65,11 +61,7 @@ TEST_F(ArrayTest, AutoResize) TEST_F(ArrayTest, PopBack) { Array array; - array.init(&allocator, 4); - - array.push(1); - array.push(2); - array.push(3); + array.init(&allocator, 4, make_initializer_list(&allocator, 1, 2, 3)); EXPECT_EQ(array.size(), 3); @@ -87,11 +79,7 @@ TEST_F(ArrayTest, PopBack) TEST_F(ArrayTest, Clear) { Array array; - array.init(&allocator, 4); - - array.push(1); - array.push(2); - array.push(3); + array.init(&allocator, 4, make_initializer_list(&allocator, 1, 2, 3)); EXPECT_EQ(array.size(), 3); @@ -135,10 +123,7 @@ TEST_F(ArrayTest, FrontAndBack) TEST_F(ArrayTest, ArrayViewWrap) { Array array; - array.init(&allocator, 4); - array.push(10); - array.push(20); - array.push(30); + array.init(&allocator, 4, make_initializer_list(&allocator, 10, 20, 30)); ArrayView view(array); diff --git a/ZEngine/tests/initializerlist_test.cpp b/ZEngine/tests/initializerlist_test.cpp index 53435f2d..9b02bc2c 100644 --- a/ZEngine/tests/initializerlist_test.cpp +++ b/ZEngine/tests/initializerlist_test.cpp @@ -25,11 +25,7 @@ class InitializerListTest : public ::testing::Test TEST_F(InitializerListTest, WithArray) { Array array; - array.init(&arena, 4); - array.push(1); - array.push(2); - array.push(3); - array.push(4); + array.init(&arena, 4, make_initializer_list(&arena, 1, 2, 3, 4)); InitializerList list(array.data(), array.size()); @@ -50,9 +46,7 @@ TEST_F(InitializerListTest, WithStrings) { Array str_array; str_array.init(&arena, 3); - str_array.push(String()); - str_array.push(String()); - str_array.push(String()); + str_array.init(&arena, 3, make_initializer_list(&arena, String(), String(), String())); str_array[0].init(&arena, "Alpha"); str_array[1].init(&arena, "Beta"); From 946b594e7b075051e31724dc21007ecbf0c2dc01 Mon Sep 17 00:00:00 2001 From: jnyfah Date: Sun, 30 Mar 2025 23:00:26 +0100 Subject: [PATCH 8/9] clang format hates me --- ZEngine/ZEngine/Core/Containers/Array.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ZEngine/ZEngine/Core/Containers/Array.h b/ZEngine/ZEngine/Core/Containers/Array.h index ed081616..2ea23275 100644 --- a/ZEngine/ZEngine/Core/Containers/Array.h +++ b/ZEngine/ZEngine/Core/Containers/Array.h @@ -3,7 +3,6 @@ #include #include - using namespace ZEngine::Core::Memory; namespace ZEngine::Core::Containers From e9c6d10672faab2cd0f82eef3a44b6c6a40c304a Mon Sep 17 00:00:00 2001 From: jnyfah Date: Sun, 30 Mar 2025 23:11:29 +0100 Subject: [PATCH 9/9] remove silly comments --- ZEngine/ZEngine/Core/Containers/Array.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/ZEngine/ZEngine/Core/Containers/Array.h b/ZEngine/ZEngine/Core/Containers/Array.h index 2ea23275..7b1a6a7a 100644 --- a/ZEngine/ZEngine/Core/Containers/Array.h +++ b/ZEngine/ZEngine/Core/Containers/Array.h @@ -31,10 +31,7 @@ namespace ZEngine::Core::Containers void init(Memory::ArenaAllocator* allocator, size_type initial_capacity, const InitializerList& list) { - // Initialize the basic array structure init(allocator, std::max(initial_capacity, list.size())); - - // Add all elements from the initializer list for (const auto& item : list) { push(item);