From fdd072770cdcef4727b35917674980eea5f22748 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Fri, 20 Sep 2024 18:03:13 +0300 Subject: [PATCH 01/13] initial version. --- .../Data/Containers/BinSearchArrayMap.hpp | 106 ++++++++++++++++++ tests/BinSearchArrayMapTest.cpp | 42 +++++++ 2 files changed, 148 insertions(+) create mode 100644 openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp create mode 100644 tests/BinSearchArrayMapTest.cpp diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp new file mode 100644 index 0000000..ee14317 --- /dev/null +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -0,0 +1,106 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include +#include +#include +#include + +namespace OpenVulkano +{ + template, typename Vec = std::vector, + typename = std::enable_if_t::value>> + class BinSearchArrayMap + { + public: + BinSearchArrayMap() = default; + ~BinSearchArrayMap() = default; + + void Insert(K key, V value) noexcept + { + // Check if the key is bigger than the last element + if (m_data.empty() || key > m_data.back().first) + { + m_data.emplace_back(key, value); + return; + } + + throw std::runtime_error("Key cannot be lesser than the last used key."); + } + + template void Emplace(K key, Args... args) + { + // Check if the key is bigger than the last element + if (m_data.empty() || key > m_data.back().first) + { + m_data.emplace_back(key, V(args...)); + return; + } + + throw std::runtime_error("Key cannot be lesser than the last used key."); + } + + void Remove(K key) noexcept + { + auto it = std::lower_bound(m_data.begin(), m_data.end(), key, + [](const auto& pair, const K& key) { return pair.first < key; }); + + if (it != m_data.end()) + { + m_data.erase(it); + } + else + { + throw std::runtime_error("Key not found."); + } + } + + void Size() const noexcept { m_data.size(); } + + V& operator[](K key) noexcept + { + auto it = std::lower_bound(m_data.begin(), m_data.end(), key, + [](const auto& pair, const K& key) { return pair.first < key; }); + + return it->second; + } + + V& Get(K key) noexcept { + auto it = std::lower_bound(m_data.begin(), m_data.end(), key, + [](const auto& pair, const K& key) { return pair.first < key; }); + + if (it != m_data.end()) + { + return it->second; + } + else + { + throw std::runtime_error("Key not found."); + } + } + + bool Contains(K key) const noexcept + { + auto it = std::lower_bound(m_data.begin(), m_data.end(), key, + [](const auto& pair, const K& key) { return pair.first < key; }); + + return it != m_data.end(); + } + + bool Contains(V& value) const noexcept + { + auto it = + std::find_if(m_data.begin(), m_data.end(), [&value](const auto& pair) { return pair.second == value; }); + + return it != m_data.end(); + } + + private: + Vec m_data; + }; +} diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp new file mode 100644 index 0000000..ea5e4e5 --- /dev/null +++ b/tests/BinSearchArrayMapTest.cpp @@ -0,0 +1,42 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include + +#include +#include +#include +#include + +#include "Data/Containers/BinSearchArrayMap.hpp" + +using namespace OpenVulkano; + +TEST_CASE("BinSearchArrayMap") +{ + std::vector> data; + data.push_back(std::make_pair(1, "One")); + data.push_back(std::make_pair(2, "Two")); + data.push_back(std::make_pair(6, "Three")); + data.push_back(std::make_pair(8, "Four")); + data.push_back(std::make_pair(10, "Five")); + + auto wtf = + std::lower_bound(data.begin(), data.end(), 10, [](const auto& pair, const int& key) { return pair.first < key; }); + + auto test = *wtf; + REQUIRE(test.first == 10); + REQUIRE(test.second == "Five"); + + BinSearchArrayMap map; + map.Insert(1, "One"); + map.Insert(2, "Two"); + map.Insert(6, "Three"); + map.Insert(8, "Four"); + map.Insert(10, "Five"); + + REQUIRE(map[6] == "Three"); +} From 02d84af90762ee6874ef76b52be0b61741c627ed Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Mon, 23 Sep 2024 17:00:07 +0300 Subject: [PATCH 02/13] -first draft of BinSearchArrayMap --- openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp | 7 ++++--- tests/BinSearchArrayMapTest.cpp | 3 ++- tests/MemFileTests.cpp | 3 --- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index ee14317..cf8629b 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -33,7 +33,7 @@ namespace OpenVulkano throw std::runtime_error("Key cannot be lesser than the last used key."); } - template void Emplace(K key, Args... args) + template void Emplace(K key, Args... args) { // Check if the key is bigger than the last element if (m_data.empty() || key > m_data.back().first) @@ -45,7 +45,7 @@ namespace OpenVulkano throw std::runtime_error("Key cannot be lesser than the last used key."); } - void Remove(K key) noexcept + void Remove(K key) noexcept { auto it = std::lower_bound(m_data.begin(), m_data.end(), key, [](const auto& pair, const K& key) { return pair.first < key; }); @@ -70,7 +70,8 @@ namespace OpenVulkano return it->second; } - V& Get(K key) noexcept { + V& Get(K key) noexcept + { auto it = std::lower_bound(m_data.begin(), m_data.end(), key, [](const auto& pair, const K& key) { return pair.first < key; }); diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp index ea5e4e5..8661947 100644 --- a/tests/BinSearchArrayMapTest.cpp +++ b/tests/BinSearchArrayMapTest.cpp @@ -12,6 +12,7 @@ #include #include "Data/Containers/BinSearchArrayMap.hpp" +#include "Data/Containers/StableVector.hpp" using namespace OpenVulkano; @@ -26,7 +27,6 @@ TEST_CASE("BinSearchArrayMap") auto wtf = std::lower_bound(data.begin(), data.end(), 10, [](const auto& pair, const int& key) { return pair.first < key; }); - auto test = *wtf; REQUIRE(test.first == 10); REQUIRE(test.second == "Five"); @@ -39,4 +39,5 @@ TEST_CASE("BinSearchArrayMap") map.Insert(10, "Five"); REQUIRE(map[6] == "Three"); + REQUIRE(map[10] == "Five"); } diff --git a/tests/MemFileTests.cpp b/tests/MemFileTests.cpp index 117ffa5..3cb433e 100644 --- a/tests/MemFileTests.cpp +++ b/tests/MemFileTests.cpp @@ -95,7 +95,6 @@ TEST_CASE("MemMappedFileWrite") OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE); REQUIRE(helper.Data() != nullptr); std::string testData((char*) helper.Data()); - printf("size: %llu", helper.Size()); helper.Close(); std::ifstream file(path, std::ios::binary); @@ -112,8 +111,6 @@ TEST_CASE("MemMappedFileWrite") } REQUIRE(streamData.size() == testData.size()); - - printf("helper size: %llu\n", helper.Size()); } SECTION("Actual Size") From 090bfcf48c0d579c5b7c9f518dfc7f801c7a58ff Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Mon, 23 Sep 2024 17:00:48 +0300 Subject: [PATCH 03/13] std like protocols to make it work with std::algo for StableVector.hpp --- .../Data/Containers/StableVector.hpp | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index ea57fa3..c2939d8 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -76,6 +76,27 @@ namespace OpenVulkano return temp; } + Iterator operator--() + { + --m_index; + MovetoNextValidChunk(); + return *this; + } + + Iterator operator--(int) + { + Iterator temp = *this; + --(*this); + return temp; + } + + template Iterator operator=(const Init& other) + { + m_ptr = other.m_ptr; + m_index = other.m_index; + return *this; + } + bool operator==(const Iterator& other) const { return m_ptr == other.m_ptr && m_index == other.m_index; } bool operator!=(const Iterator& other) const { return !(*this == other); } @@ -216,6 +237,16 @@ namespace OpenVulkano m_currentSize++; } + /** + * std version of PushBack(const T& value) + */ + void push_back(const T& value) { PushBack(value); } + + /** + * std version of PushBack(T&& value) + */ + void push_back(T&& value) { PushBack(std::move(value)); } + template void Emplace(Args&&... args) { VectorChunk* currentChunk = m_firstChunk; @@ -255,6 +286,11 @@ namespace OpenVulkano m_currentSize++; } + /** + * std version of EmplaceBack(Args&&... args) + */ + template void emplace_back(Args&&... args) { EmplaceBack(std::forward(args)...); } + /** * Pops the last element of the StableVector * @@ -279,6 +315,39 @@ namespace OpenVulkano m_currentSize--; } + /** + * std version of PopBack() + */ + void pop_back() { PopBack(); } + + constexpr T& Back() const + { + if (m_currentSize == 0) + { + throw std::out_of_range("Vector is empty!"); + } + return m_lastChunk->m_data[m_lastChunk->m_lastUsedIndex]; + } + + constexpr T& Front() const + { + if (m_currentSize == 0) + { + throw std::out_of_range("Vector is empty!"); + } + return m_firstChunk->m_data[0]; + } + + /** + * std version of Back() + */ + constexpr T& back() const { return Back(); } + + /** + * std version of Front() + */ + constexpr T& front() const { return Front(); } + void Remove(size_t index) { size_t localIndex = index; @@ -332,6 +401,7 @@ namespace OpenVulkano return vec; } + T& At(size_t index) const { if (index >= Size()) [[unlikely]] @@ -339,6 +409,9 @@ namespace OpenVulkano return (*this)[index]; } + bool Empty() const { return m_currentSize == 0; } + bool empty() const { return Empty(); } + T& operator[](size_t index) const { VectorChunk* chunk = m_firstChunk; From 41b5a046bee3fe77750fa017a5856e56c0be1fca Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Thu, 26 Sep 2024 15:48:19 +0300 Subject: [PATCH 04/13] Fix on stable vector. --- openVulkanoCpp/Data/Containers/StableVector.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index c2939d8..e97ca2a 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -382,6 +382,16 @@ namespace OpenVulkano } } + /** + * std version of Remove(size_t index) + */ + void erase(size_t index) { Remove(index); } + + /** + * std version of Remove(const T& value) + */ + void erase(const T& value) { Remove(value); } + std::vector ToVector() const { std::vector vec; @@ -430,7 +440,10 @@ namespace OpenVulkano } size_t Size() const { return m_currentSize; } + size_t size() const { return Size(); } + size_t Capacity() const { return m_totalCap; } + size_t capacity() const { return Capacity(); } void Clear() { From fc675f9f50a1fafd636d896306c45877c2c01a0d Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Thu, 26 Sep 2024 15:48:37 +0300 Subject: [PATCH 05/13] fix on BinSearchArrayMap (W.I.P) --- .../Data/Containers/BinSearchArrayMap.hpp | 92 ++++++++----------- tests/BinSearchArrayMapTest.cpp | 26 +++--- 2 files changed, 48 insertions(+), 70 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index cf8629b..00f6f66 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -18,10 +18,7 @@ namespace OpenVulkano class BinSearchArrayMap { public: - BinSearchArrayMap() = default; - ~BinSearchArrayMap() = default; - - void Insert(K key, V value) noexcept + void Insert(K key, const V& value) { // Check if the key is bigger than the last element if (m_data.empty() || key > m_data.back().first) @@ -33,73 +30,58 @@ namespace OpenVulkano throw std::runtime_error("Key cannot be lesser than the last used key."); } - template void Emplace(K key, Args... args) + template void Emplace(K key, Args&&... args) { // Check if the key is bigger than the last element if (m_data.empty() || key > m_data.back().first) { - m_data.emplace_back(key, V(args...)); + m_data.emplace_back(key, std::forward(args)...); return; } throw std::runtime_error("Key cannot be lesser than the last used key."); } - void Remove(K key) noexcept + void Remove(const K key) { - auto it = std::lower_bound(m_data.begin(), m_data.end(), key, - [](const auto& pair, const K& key) { return pair.first < key; }); + auto& it = FindPair(key); + m_data.erase(it); + } - if (it != m_data.end()) + size_t Size() const { return m_data.size(); } + + V& operator[](const K key) noexcept { return Get(key); } + + V& Get(const K key) { return FindPair(key).second; } + + Pair& FindPair(const K key) + { + int low = 0; + int high = m_data.size() - 1; + + while (low <= high) { - m_data.erase(it); - } - else - { - throw std::runtime_error("Key not found."); + int mid = low + (high - low) / 2; + + if (m_data[mid].first == key) + { + return m_data[mid]; // The difference + } + else if (m_data[mid].first < key) + { + low = mid + 1; + } + else + { + high = mid - 1; + } } + + throw std::runtime_error("Key not found."); } - void Size() const noexcept { m_data.size(); } - - V& operator[](K key) noexcept - { - auto it = std::lower_bound(m_data.begin(), m_data.end(), key, - [](const auto& pair, const K& key) { return pair.first < key; }); - - return it->second; - } - - V& Get(K key) noexcept - { - auto it = std::lower_bound(m_data.begin(), m_data.end(), key, - [](const auto& pair, const K& key) { return pair.first < key; }); - - if (it != m_data.end()) - { - return it->second; - } - else - { - throw std::runtime_error("Key not found."); - } - } - - bool Contains(K key) const noexcept - { - auto it = std::lower_bound(m_data.begin(), m_data.end(), key, - [](const auto& pair, const K& key) { return pair.first < key; }); - - return it != m_data.end(); - } - - bool Contains(V& value) const noexcept - { - auto it = - std::find_if(m_data.begin(), m_data.end(), [&value](const auto& pair) { return pair.second == value; }); - - return it != m_data.end(); - } + bool Contains(const K key) const { return true; } + bool Contains(const V& value) const { return true; } private: Vec m_data; diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp index 8661947..7a32523 100644 --- a/tests/BinSearchArrayMapTest.cpp +++ b/tests/BinSearchArrayMapTest.cpp @@ -18,26 +18,22 @@ using namespace OpenVulkano; TEST_CASE("BinSearchArrayMap") { - std::vector> data; - data.push_back(std::make_pair(1, "One")); - data.push_back(std::make_pair(2, "Two")); - data.push_back(std::make_pair(6, "Three")); - data.push_back(std::make_pair(8, "Four")); - data.push_back(std::make_pair(10, "Five")); + BinSearchArrayMap, StableVector>> map; - auto wtf = - std::lower_bound(data.begin(), data.end(), 10, [](const auto& pair, const int& key) { return pair.first < key; }); - auto test = *wtf; - REQUIRE(test.first == 10); - REQUIRE(test.second == "Five"); - - BinSearchArrayMap map; map.Insert(1, "One"); map.Insert(2, "Two"); map.Insert(6, "Three"); map.Insert(8, "Four"); map.Insert(10, "Five"); - REQUIRE(map[6] == "Three"); - REQUIRE(map[10] == "Five"); + REQUIRE(map.Get(1) == "One"); + REQUIRE(map.Get(2) == "Two"); + REQUIRE(map.Get(6) == "Three"); + REQUIRE(map.Get(8) == "Four"); + REQUIRE(map.Get(10) == "Five"); + + REQUIRE(map.Size() == 5); + + map.Remove(6); + REQUIRE(map.Size() == 4); } From 6661e9e9af3f4ce4494a8d70550b0fb0142ba92a Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Thu, 26 Sep 2024 15:49:38 +0300 Subject: [PATCH 06/13] size_t over int on BinSearchArrayMap --- openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index 00f6f66..31c07e4 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -56,12 +56,12 @@ namespace OpenVulkano Pair& FindPair(const K key) { - int low = 0; - int high = m_data.size() - 1; + size_t low = 0; + size_t high = m_data.size() - 1; while (low <= high) { - int mid = low + (high - low) / 2; + size_t mid = low + (high - low) / 2; if (m_data[mid].first == key) { From eb2ca2ff5a62388cd46018d99f51db3bd7528570 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Thu, 3 Oct 2024 18:15:48 +0300 Subject: [PATCH 07/13] New StableVector but Iterator is missing. --- .../Data/Containers/BinSearchArrayMap.hpp | 73 +- .../Data/Containers/StableVector.hpp | 740 +++++++++--------- tests/BinSearchArrayMapTest.cpp | 104 ++- tests/StableVectorTest.cpp | 370 ++++----- 4 files changed, 716 insertions(+), 571 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index 31c07e4..00ba69a 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -13,8 +13,8 @@ namespace OpenVulkano { - template, typename Vec = std::vector, - typename = std::enable_if_t::value>> + template class Pair = std::pair, + template class Vec = std::vector, typename = std::enable_if_t::value>> class BinSearchArrayMap { public: @@ -44,8 +44,8 @@ namespace OpenVulkano void Remove(const K key) { - auto& it = FindPair(key); - m_data.erase(it); + std::streamsize index = FindIndexInVector(key); + m_data.erase(m_data.begin() + index); } size_t Size() const { return m_data.size(); } @@ -54,10 +54,10 @@ namespace OpenVulkano V& Get(const K key) { return FindPair(key).second; } - Pair& FindPair(const K key) + Pair& FindPair(const K key) { size_t low = 0; - size_t high = m_data.size() - 1; + size_t high = m_data.size(); while (low <= high) { @@ -65,7 +65,33 @@ namespace OpenVulkano if (m_data[mid].first == key) { - return m_data[mid]; // The difference + return m_data[mid]; + } + else if (m_data[mid].first < key) + { + low = mid + 1; + } + else + { + high = mid - 1; + } + } + + throw std::runtime_error("Key not found."); + } + + std::streamsize FindIndexInVector(const K key) + { + size_t low = 0; + size_t high = m_data.size(); + + while (low <= high) + { + size_t mid = low + (high - low) / 2; + + if (m_data[mid].first == key) + { + return mid; } else if (m_data[mid].first < key) { @@ -77,13 +103,38 @@ namespace OpenVulkano } } - throw std::runtime_error("Key not found."); + return -1; } - bool Contains(const K key) const { return true; } - bool Contains(const V& value) const { return true; } + bool Contains(const K key) const noexcept + { + size_t low = 0; + size_t high = m_data.size(); + + while (low <= high) + { + size_t mid = low + (high - low) / 2; + + if (m_data[mid].first == key) + { + return true; + } + else if (m_data[mid].first < key) + { + low = mid + 1; + } + else + { + high = mid - 1; + } + } + + return false; + } + + void Clear() { m_data.clear(); } private: - Vec m_data; + Vec> m_data; }; } diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index e97ca2a..f42c313 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -1,3 +1,9 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + #pragma once #include "Base/Wrapper.hpp" @@ -9,6 +15,8 @@ #include #include +#include + #pragma warning(push) #pragma warning(disable : 4200) #pragma warning(disable : 6011) @@ -22,28 +30,31 @@ namespace OpenVulkano * * @throw Please know that this vector creates array gaps when you remove an element. */ - template class StableVector + template class StableVector { struct VectorChunk { - VectorChunk* m_prev = nullptr; - VectorChunk* m_next = nullptr; - size_t m_chunkSize; - int64_t m_lastUsedIndex; - bool* m_fill; - T m_data[0]; + VectorChunk* m_next = nullptr; // Next chunk + VectorChunk* m_prev = nullptr; // Previous chunk - VectorChunk(size_t size) : m_chunkSize(size), m_lastUsedIndex(-1) + size_t m_size; // Size of the chunk + size_t m_capacity; // Capacity of the chunk + size_t m_nextIndex; // Next index to insert + size_t m_gapCount; // Count of emptied gaps in the chunk + bool* m_occupiedIndices; // filled gaps array + T m_data[0]; // data array + + VectorChunk(size_t size) : m_size(0), m_capacity(size), m_nextIndex(0), m_gapCount(0) { - m_fill = reinterpret_cast(m_data + size); - memset(m_fill, 0, size * sizeof(bool)); + m_occupiedIndices = reinterpret_cast(m_data + size); + memset(m_occupiedIndices, 0, size * sizeof(bool)); } ~VectorChunk() { - for (size_t i = 0; i < m_chunkSize; i++) + for (size_t i = 0; i < m_size; i++) { - if (m_fill[i]) + if (m_occupiedIndices[i]) { m_data[i].~T(); } @@ -51,499 +62,506 @@ namespace OpenVulkano m_prev = nullptr; m_next = nullptr; } + + size_t GetRealIndex(size_t reqIndex) + { + if (m_gapCount == 0) + { + return reqIndex; + } + + size_t gapCount = 0; + for (size_t i = 0; i < reqIndex; i++) + { + if (!m_occupiedIndices[i]) + { + gapCount++; + } + } + + return reqIndex + gapCount; + } + + T& GetAlignedData(size_t index) + { + size_t realIndex = GetRealIndex(index); + + for (size_t i = realIndex; i < m_capacity; i++) + { + if (m_occupiedIndices[i]) + { + return m_data[i]; + } + } + } + + size_t GetLastOccupiedIndex() + { + for (size_t i = m_capacity - 1; i >= 0; i--) + { + if (m_occupiedIndices[i]) + { + return i; + } + } + + return 0; + } }; public: class Iterator { public: - Iterator(VectorChunk* ptr, size_t index = 0) : m_ptr(ptr), m_index(index) {} + Iterator(VectorChunk* chunk, size_t index) : m_chunk(chunk), m_index(index) {} - T& operator*() { return m_ptr->m_data[m_index]; } - T* operator->() { return &m_ptr->m_data[m_index]; } + T& operator*() { return m_chunk->GetAlignedData(m_index); } + T* operator->() { return &m_chunk->GetAlignedData(m_index); } - Iterator operator++() + Iterator& operator++() { ++m_index; - MovetoNextValidChunk(); + MoveToNextChunk(); return *this; } Iterator operator++(int) { Iterator temp = *this; - ++(*this); + ++m_index; + MoveToNextChunk(); return temp; } - Iterator operator--() + Iterator& operator--() { --m_index; - MovetoNextValidChunk(); + MoveToPrevChunk(); return *this; } Iterator operator--(int) { Iterator temp = *this; - --(*this); + --m_index; + MoveToPrevChunk(); return temp; } - template Iterator operator=(const Init& other) + Iterator operator+(size_t n) { - m_ptr = other.m_ptr; - m_index = other.m_index; - return *this; + Iterator temp = *this; + temp.m_index += n; + temp.MoveToNextChunk(); + return temp; } - bool operator==(const Iterator& other) const { return m_ptr == other.m_ptr && m_index == other.m_index; } - bool operator!=(const Iterator& other) const { return !(*this == other); } - - private: - void MovetoNextValidChunk() + Iterator operator-(size_t n) { - while (m_ptr && (m_index > m_ptr->m_chunkSize || !m_ptr->m_fill[m_index])) - { - if (m_index >= m_ptr->m_chunkSize) - { - m_ptr = m_ptr->m_next; - m_index = 0; - } - else ++m_index; - } + Iterator temp = *this; + temp.m_index -= n; + temp.MoveToPrevChunk(); + return temp; + } - if (m_ptr && m_index >= m_ptr->m_chunkSize) + bool operator==(const Iterator& other) const + { + return m_chunk == other.m_chunk && m_index == other.m_index; + } + + bool operator!=(const Iterator& other) const + { + return m_chunk != other.m_chunk || m_index != other.m_index; + } + + protected: + void MoveToNextChunk() + { + while (m_chunk && m_index > m_chunk->m_size) { - m_ptr = m_ptr->m_next; - m_index = 0; - MovetoNextValidChunk(); + m_index -= m_chunk->m_size; + m_chunk = m_chunk->m_next; } } + void MoveToPrevChunk() {} + private: - VectorChunk* m_ptr; + VectorChunk* m_chunk; size_t m_index; }; public: - StableVector() : m_firstChunk(nullptr), m_lastChunk(nullptr) + StableVector() : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) { - VectorChunk* chunk = SpawnChunk(DEFAULT_CHUNK_SIZE); - m_firstChunk = chunk; - m_lastChunk = chunk; - m_currentSize = 0; - m_totalCap = DEFAULT_CHUNK_SIZE; + m_FirstChunk = Grow(DEFAULT_CHUNK_SIZE); + m_LastChunk = m_FirstChunk; + m_Capacity = DEFAULT_CHUNK_SIZE; + } + + StableVector(size_t size) : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + { + m_FirstChunk = Grow(size); + m_LastChunk = m_FirstChunk; + m_Capacity = size; + } + + StableVector(size_t size, const T& value) + : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + { + m_FirstChunk = Grow(size); + m_LastChunk = m_FirstChunk; + m_Capacity = size; + + for (size_t i = 0; i < size; i++) + { + PushBack(value); + } + } + + StableVector(std::initializer_list list) + : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + { + m_FirstChunk = Grow(list.size()); + m_LastChunk = m_FirstChunk; + m_Capacity = list.size(); + + for (const T& value: list) + { + PushBack(value); + } } StableVector(const StableVector& copy) + : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) { - m_firstChunk = nullptr; - m_lastChunk = nullptr; - m_currentSize = 0; - m_totalCap = 0; + m_FirstChunk = Grow(copy.m_Capacity); // One big chunk to make Stable contiguous. + m_LastChunk = m_FirstChunk; + m_Capacity = copy.m_Capacity; - VectorChunk* currentChunk = copy.m_firstChunk; - while (currentChunk) + for (size_t i = 0; i < copy.Size(); i++) { - for (size_t i = 0; i < currentChunk->m_chunkSize; i++) - { - if (currentChunk->m_fill[i]) { PushBack(currentChunk->m_data[i]); } - } - - currentChunk = currentChunk->m_next; + PushBack(copy.At(i)); } } StableVector(StableVector&& move) noexcept + : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) { - m_firstChunk = move.m_firstChunk; - m_lastChunk = move.m_lastChunk; - m_currentSize = move.m_currentSize; - m_totalCap = move.m_totalCap; + m_FirstChunk = move.m_FirstChunk; + m_LastChunk = move.m_LastChunk; + m_Size = move.m_Size; + m_Capacity = move.m_Capacity; - move.m_firstChunk = nullptr; - move.m_lastChunk = nullptr; - move.m_currentSize = 0; - move.m_totalCap = 0; + move.m_FirstChunk = nullptr; + move.m_LastChunk = nullptr; + move.m_Size = 0; + move.m_Capacity = 0; } ~StableVector() { - VectorChunk* currentChunk = m_firstChunk; + VectorChunk* currentChunk = m_FirstChunk; while (currentChunk) { - VectorChunk* temp = currentChunk; - currentChunk = currentChunk->m_next; - temp->~VectorChunk(); - ::operator delete(temp); + VectorChunk* nextChunk = currentChunk->m_next; + currentChunk->~VectorChunk(); + ::operator delete(currentChunk); + currentChunk = nextChunk; } } - /** - * Adds the value to the first empty slot in the StableVector - * - * @param value - The value to be added - */ - void Add(const T& value) - { - VectorChunk* currentChunk = m_firstChunk; - while (currentChunk) - { - for (size_t i = 0; i < currentChunk->m_chunkSize; i++) - { - if (!currentChunk->m_fill[i]) - { - currentChunk->m_data[i] = value; - currentChunk->m_fill[i] = true; - m_currentSize++; - - if (i > currentChunk->m_lastUsedIndex) currentChunk->m_lastUsedIndex = i; - return; - } - } - - currentChunk = currentChunk->m_next; - } - - VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR)); - - new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(value); - m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; - m_currentSize++; - } - void PushBack(const T& value) { - if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize) + if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) { - VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR)); + VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); + m_LastChunk->m_next = newChunk; + newChunk->m_prev = m_LastChunk; + m_LastChunk = newChunk; } - new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(value); - m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; - m_currentSize++; + new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(value); + m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true; + m_LastChunk->m_nextIndex++; + m_LastChunk->m_size++; + m_Size++; } + /// std version of push_back(const T& value) + void push_back(const T& value) { PushBack(value); } + void PushBack(T&& value) noexcept { - if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize) + if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) { - VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR)); + VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); + m_LastChunk->m_next = newChunk; + newChunk->m_prev = m_LastChunk; + m_LastChunk = newChunk; } - new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::move(value)); - m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; - m_currentSize++; + new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(std::move(value)); + m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true; + m_LastChunk->m_nextIndex++; + m_LastChunk->m_size++; + m_Size++; } - /** - * std version of PushBack(const T& value) - */ - void push_back(const T& value) { PushBack(value); } + /// std version of push_back(T&& value) + void push_back(T&& value) { PushBack(value); } - /** - * std version of PushBack(T&& value) - */ - void push_back(T&& value) { PushBack(std::move(value)); } - - template void Emplace(Args&&... args) + // Checks the first available gap and inserts. If no gap it works like push_back(const T& value) + void Push(const T& value) { - VectorChunk* currentChunk = m_firstChunk; - + VectorChunk* currentChunk = m_FirstChunk; while (currentChunk) { - for (size_t i = 0; i < currentChunk->m_chunkSize; i++) + if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap { - if (!currentChunk->m_fill[i]) + for (size_t i = 0; i < currentChunk->m_capacity; i++) { - currentChunk->m_data[i] = T(std::forward(args)...); - currentChunk->m_fill[i] = true; - m_currentSize++; - - if (i > currentChunk->m_lastUsedIndex) currentChunk->m_lastUsedIndex = i; - return; + if (!currentChunk->m_occupiedIndices[i]) + { + new (¤tChunk->m_data[i]) T(value); + currentChunk->m_occupiedIndices[i] = true; + currentChunk->m_size++; + currentChunk->m_gapCount--; + m_Size++; + return; + } } } - - currentChunk = currentChunk->m_next; } - VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR)); + PushBack(value); + } - new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::forward(args)...); - m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; - m_currentSize++; + // Checks the first available gap and inserts. If no gap it works like push_back(T&& value) + void Push(T&& value) noexcept + { + VectorChunk* currentChunk = m_FirstChunk; + while (currentChunk) + { + if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap + { + for (size_t i = 0; i < currentChunk->m_capacity; i++) + { + if (!currentChunk->m_occupiedIndices[i]) + { + new (¤tChunk->m_data[i]) T(std::move(value)); + currentChunk->m_occupiedIndices[i] = true; + currentChunk->m_size++; + currentChunk->m_gapCount--; + m_Size++; + return; + } + } + } + } + + PushBack(std::move(value)); } template void EmplaceBack(Args&&... args) { - if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize) - VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR)); - - new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::forward(args)...); - m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; - m_currentSize++; - } - - /** - * std version of EmplaceBack(Args&&... args) - */ - template void emplace_back(Args&&... args) { EmplaceBack(std::forward(args)...); } - - /** - * Pops the last element of the StableVector - * - * @throw Please know that this pop function also reduces the chunk's lastUsedIndex - */ - void PopBack() - { - if (m_currentSize == 0) return; - - if (m_lastChunk->m_lastUsedIndex == -1) + if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) { - VectorChunk* temp = m_lastChunk; - m_lastChunk = m_lastChunk->m_prev; - m_lastChunk->m_next = nullptr; - temp->~VectorChunk(); - ::operator delete(temp); + VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); + m_LastChunk->m_next = newChunk; + newChunk->m_prev = m_LastChunk; + m_LastChunk = newChunk; } - m_lastChunk->m_data[m_lastChunk->m_lastUsedIndex].~T(); - m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = false; - m_lastChunk->m_lastUsedIndex--; - m_currentSize--; + new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(std::forward(args)...); + m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true; + m_LastChunk->m_nextIndex++; + m_LastChunk->m_size++; + m_Size++; } - /** - * std version of PopBack() - */ + /// std version of emplace_back + template void emplace_back(Args&&... args) { EmplaceBack(std::forward(args)...); } + + // Checks the first available gap and inserts. If no gap it works like emplace_back(Args&&... args) + template void Emplace(Args&&... args) + { + VectorChunk* currentChunk = m_FirstChunk; + while (currentChunk) + { + if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap + { + for (size_t i = 0; i < currentChunk->m_capacity; i++) + { + if (!currentChunk->m_occupiedIndices[i]) + { + new (¤tChunk->m_data[i]) T(std::forward(args)...); + currentChunk->m_occupiedIndices[i] = true; + currentChunk->m_size++; + currentChunk->m_gapCount--; + m_Size++; + return; + } + } + } + } + + EmplaceBack(std::forward(args)...); + } + + void PopBack() + { + if (m_Size == 0) + { + return; // return? or make + } + + m_LastChunk->m_data[m_LastChunk->m_nextIndex - 1].~T(); + m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex - 1] = false; + m_LastChunk->m_nextIndex--; + m_LastChunk->m_size--; + m_Size--; + } + + /// std version of pop_back void pop_back() { PopBack(); } constexpr T& Back() const { - if (m_currentSize == 0) + if (m_Size == 0) { - throw std::out_of_range("Vector is empty!"); + throw std::out_of_range("Index out of range"); } - return m_lastChunk->m_data[m_lastChunk->m_lastUsedIndex]; + + return m_LastChunk->m_data[m_LastChunk->GetLastOccupiedIndex()]; } + /// std version of back + constexpr T& back() const { return Back(); } + constexpr T& Front() const { - if (m_currentSize == 0) + if (m_Size == 0) { - throw std::out_of_range("Vector is empty!"); + throw std::out_of_range("Index out of range"); } - return m_firstChunk->m_data[0]; + + return m_FirstChunk->m_data[0]; } - /** - * std version of Back() - */ - constexpr T& back() const { return Back(); } - - /** - * std version of Front() - */ + /// std version of front constexpr T& front() const { return Front(); } void Remove(size_t index) { - size_t localIndex = index; - VectorChunk* chunk = GetChunk(localIndex); - - if (chunk) + auto handle = FindChunk(index); + if (!handle.first) { - chunk->m_data[localIndex].~T(); - chunk->m_fill[localIndex] = false; - m_currentSize--; + throw std::out_of_range("Index out of range"); } - else throw std::out_of_range("Index out of range!"); + + size_t realIndex = handle.first->GetRealIndex(handle.second); + if (realIndex >= handle.first->m_size) + { + throw std::out_of_range("Index out of range"); + } + + handle.first->m_data[realIndex].~T(); + handle.first->m_occupiedIndices[realIndex] = false; + handle.first->m_size--; + handle.first->m_gapCount++; + m_Size--; } - void Remove(const T& value) + // Temporary non correct solution. (DONT MIND THIS ERASE) + void erase(Iterator it) { - VectorChunk* currentChunk = m_firstChunk; + size_t index = 0; + VectorChunk* currentChunk = m_FirstChunk; while (currentChunk) { - for (size_t i = 0; i < currentChunk->m_chunkSize; i++) + if (index + currentChunk->m_size > it.m_index) { - if (currentChunk->m_fill[i] && currentChunk->m_data[i] == value) - { - currentChunk->m_data[i].~T(); - currentChunk->m_fill[i] = false; - m_currentSize--; - return; - } + size_t realIndex = currentChunk->GetRealIndex(it.m_index); + currentChunk->m_data[realIndex].~T(); + currentChunk->m_occupiedIndices[realIndex] = false; + currentChunk->m_size--; + currentChunk->m_gapCount++; + m_Size--; + return; } + index += currentChunk->m_size; currentChunk = currentChunk->m_next; } } - /** - * std version of Remove(size_t index) - */ - void erase(size_t index) { Remove(index); } - - /** - * std version of Remove(const T& value) - */ - void erase(const T& value) { Remove(value); } - - std::vector ToVector() const + T& operator[](size_t index) { return At(index); } + T& At(size_t index) { - std::vector vec; - VectorChunk* currentChunk = m_firstChunk; + if (index >= m_Size) [[unlikely]] + { + throw std::out_of_range("Index out of range"); + } + + auto handle = FindChunk(index); + return handle.first->GetAlignedData(handle.second); + } + + /// std version of at + T& at(size_t index) { return At(index); } + + size_t Size() const noexcept { return m_Size; } + /// std version of size + size_t size() const noexcept { return m_Size; } + + size_t Capacity() const noexcept { return m_Capacity; } + /// std version of capacity + size_t capacity() const noexcept { return m_Capacity; } + + bool Empty() const noexcept { return m_Size == 0; } + /// std version of empty + bool empty() const noexcept { return m_Size == 0; } + + Iterator begin() { return Iterator(m_FirstChunk, 0); } + Iterator end() { return Iterator(m_LastChunk, m_LastChunk->m_nextIndex - 1); } + + const Iterator& cbegin() { return Iterator(m_FirstChunk, 0); } + const Iterator& cend() { return Iterator(m_LastChunk, m_LastChunk->m_nextIndex - 1); } + + protected: + VectorChunk* Grow(size_t requestSize) + { + VectorChunk* newChunk = static_cast( + ::operator new(sizeof(VectorChunk) + requestSize * sizeof(T) + requestSize * sizeof(bool))); + new (newChunk) VectorChunk(requestSize); + + return newChunk; + } + + std::pair FindChunk(size_t index) + { + size_t leftIndex = index; + VectorChunk* currentChunk = m_FirstChunk; while (currentChunk) { - for (size_t i = 0; i < currentChunk->m_chunkSize; i++) + if (leftIndex < currentChunk->m_size) { - if (currentChunk->m_fill[i]) - { - vec.push_back(currentChunk->m_data[i]); - } + return { currentChunk, leftIndex }; } + leftIndex -= currentChunk->m_size; currentChunk = currentChunk->m_next; } - return vec; - } - - T& At(size_t index) const - { - if (index >= Size()) [[unlikely]] - throw std::out_of_range("Index out of range!"); - return (*this)[index]; - } - - bool Empty() const { return m_currentSize == 0; } - bool empty() const { return Empty(); } - - T& operator[](size_t index) const - { - VectorChunk* chunk = m_firstChunk; - size_t localIndex = index; - while (chunk) - { - if (localIndex > chunk->m_chunkSize - 1) - { - localIndex -= (chunk->m_chunkSize); - chunk = chunk->m_next; - } - else break; - } - - return chunk->m_data[localIndex]; - } - - size_t Size() const { return m_currentSize; } - size_t size() const { return Size(); } - - size_t Capacity() const { return m_totalCap; } - size_t capacity() const { return Capacity(); } - - void Clear() - { - VectorChunk* currentChunk = m_firstChunk; - while (currentChunk) - { - VectorChunk* temp = currentChunk; - currentChunk = currentChunk->m_next; - delete temp; - } - - m_firstChunk = nullptr; - m_lastChunk = nullptr; - m_currentSize = 0; - m_totalCap = DEFAULT_CHUNK_SIZE; - - m_firstChunk = SpawnChunk(DEFAULT_CHUNK_SIZE); - m_lastChunk = m_firstChunk; - } - - StableVector& operator=(const StableVector& copy) - { - if (this == ©) return *this; - - Clear(); - - m_firstChunk = nullptr; - m_lastChunk = nullptr; - m_currentSize = 0; - m_totalCap = 0; - - VectorChunk* currentChunk = copy.m_firstChunk; - - for (auto it = copy.begin(); it != copy.end(); ++it) PushBack(*it); - } - - StableVector& operator=(StableVector&& move) noexcept - { - if (this == &move) return *this; - - Clear(); - - m_firstChunk = move.m_firstChunk; - m_lastChunk = move.m_lastChunk; - m_currentSize = move.m_currentSize; - m_totalCap = move.m_totalCap; - - move.m_firstChunk = nullptr; - move.m_lastChunk = nullptr; - move.m_currentSize = 0; - move.m_totalCap = 0; - - return *this; - } - - Iterator begin() { return Iterator(m_firstChunk, 0); } - Iterator end() { return Iterator(m_lastChunk, m_lastChunk->m_lastUsedIndex + 1); } - - const Iterator& cbegin() const { return Iterator(m_firstChunk, 0); } - const Iterator& cend() const { return Iterator(m_lastChunk, m_lastChunk->m_lastUsedIndex + 1); } - - private: - VectorChunk* SpawnChunk(size_t requestedSize) - { - VectorChunk* chunk = static_cast( - ::operator new(sizeof(VectorChunk) + requestedSize * sizeof(T) + requestedSize * sizeof(bool))); - new (chunk) VectorChunk(requestedSize); - - if (m_lastChunk) - { - chunk->m_prev = m_lastChunk; - m_lastChunk->m_next = chunk; - m_lastChunk = chunk; - m_totalCap += m_lastChunk->m_chunkSize; - } - - return chunk; - } - - VectorChunk* GetChunk(size_t& localIndex) - { - VectorChunk* chunk = m_firstChunk; - while (chunk) - { - if (localIndex > chunk->m_chunkSize - 1) - { - localIndex -= (chunk->m_chunkSize); - chunk = chunk->m_next; - } - else break; - } - - return chunk; + throw std::out_of_range("Index out of range"); } private: - VectorChunk* m_firstChunk; - VectorChunk* m_lastChunk; - size_t m_currentSize; - size_t m_totalCap; + VectorChunk* m_FirstChunk; + VectorChunk* m_LastChunk; + size_t m_Size; + size_t m_Capacity; }; } diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp index 7a32523..64813df 100644 --- a/tests/BinSearchArrayMapTest.cpp +++ b/tests/BinSearchArrayMapTest.cpp @@ -16,24 +16,98 @@ using namespace OpenVulkano; -TEST_CASE("BinSearchArrayMap") +TEST_CASE("BinSearchArrayMap With Default") { - BinSearchArrayMap, StableVector>> map; + SECTION("Insert") + { + BinSearchArrayMap map; - map.Insert(1, "One"); - map.Insert(2, "Two"); - map.Insert(6, "Three"); - map.Insert(8, "Four"); - map.Insert(10, "Five"); + for (int i = 0; i < 50; i++) + { + map.Insert(i, std::to_string(i)); + } - REQUIRE(map.Get(1) == "One"); - REQUIRE(map.Get(2) == "Two"); - REQUIRE(map.Get(6) == "Three"); - REQUIRE(map.Get(8) == "Four"); - REQUIRE(map.Get(10) == "Five"); + REQUIRE(map.Size() == 50); + REQUIRE(map.Get(16) == "16"); + REQUIRE(map.Get(23) == "23"); + REQUIRE(map.Get(48) == "48"); + } - REQUIRE(map.Size() == 5); + SECTION("Remove") + { + BinSearchArrayMap map; - map.Remove(6); - REQUIRE(map.Size() == 4); + for (int i = 0; i < 50; i++) + { + map.Insert(i, std::to_string(i)); + } + + map.Remove(16); + map.Remove(23); + map.Remove(48); + + REQUIRE(map[49] == "49"); + + printf("ARRAY WITH DEFAULT\n"); + for (int i = 0; i < 50; i++) + { + if (map.Contains(i)) + { + printf("index: %d, value: %s\n", i, map[i].c_str()); + } + else + { + printf("index: %d, value: %s\n", i, "EMPTY"); + } + } + } } + +//TEST_CASE("BinSearchArrayMap With StableVector") +//{ +// SECTION("Insert") +// { +// BinSearchArrayMap map; +// +// for (int i = 0; i < 50; i++) +// { +// map.Insert(i, std::to_string(i)); +// } +// +// REQUIRE(map.Size() == 50); +// REQUIRE(map.Get(16) == "16"); +// REQUIRE(map.Get(23) == "23"); +// REQUIRE(map.Get(48) == "48"); +// } +// +// SECTION("Remove") +// { +// BinSearchArrayMap map; +// +// for (int i = 0; i < 50; i++) +// { +// map.Insert(i, std::to_string(i)); +// } +// +// map.Remove(16); +// map.Remove(23); +// +// if (map.Contains(49)) +// { +// printf("index: %d, value: %s\n", 49, map[49].c_str()); +// } +// +// printf("ARRAY WITH STABLE VECTOR\n"); +// for (int i = 0; i < 50; i++) +// { +// if (map.Contains(i)) +// { +// printf("index: %d, value: %s\n", i, map[i].c_str()); +// } +// else +// { +// printf("index: %d, value: %s\n", i, "EMPTY"); +// } +// } +// } +//} \ No newline at end of file diff --git a/tests/StableVectorTest.cpp b/tests/StableVectorTest.cpp index 51b15b3..0cdb5f2 100644 --- a/tests/StableVectorTest.cpp +++ b/tests/StableVectorTest.cpp @@ -4,187 +4,189 @@ using namespace OpenVulkano; -struct Test -{ - uint32_t mValue; - Test(uint32_t value) : mValue(value) {} - Test() : mValue(0) {} -}; - -static int incrementCounter = 0; -static int decrementCounter = 0; - -struct TestCount -{ - TestCount() : m_value("") { ++incrementCounter; } - TestCount(const std::string& val) : m_value(val) { ++incrementCounter; } - TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; } - TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; } - - TestCount& operator=(const TestCount& other) - { - m_value = other.m_value; - return *this; - } - - TestCount& operator=(TestCount&& other) noexcept - { - m_value = std::move(other.m_value); - return *this; - } - - ~TestCount() { ++decrementCounter; } - - std::string m_value; -}; - -TEST_CASE("ChunkVector") -{ - SECTION("PushBack") - { - StableVector vec; - - REQUIRE(vec.Size() == 0); - REQUIRE(vec.Capacity() == 32); - - for (uint32_t i = 0; i < 100; ++i) - { - vec.PushBack(i); - } - - REQUIRE(vec.Size() == 100); - REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2 - } - - SECTION("EmplaceBack") - { - StableVector vec; - - REQUIRE(vec.Size() == 0); - REQUIRE(vec.Capacity() == 32); - - for (uint32_t i = 0; i < 100; ++i) - { - vec.EmplaceBack(i); - } - - REQUIRE(vec.Size() == 100); - - for (uint32_t i = 0; i < 100; ++i) - { - REQUIRE(vec[i].mValue == i); - } - } - - SECTION("PopBack") - { - StableVector vec; - - REQUIRE(vec.Size() == 0); - REQUIRE(vec.Capacity() == 32); - - for (uint32_t i = 0; i < 100; ++i) - { - vec.PushBack(i); - } - - REQUIRE(vec.Size() == 100); - - uint64_t tempVal = vec.Capacity(); - - for (uint32_t i = 0; i < 50; ++i) - { - vec.PopBack(); - } - - REQUIRE(vec.Size() == 50); - REQUIRE(vec.Capacity() == tempVal); - } - - SECTION("Clear") - { - StableVector vec; - - REQUIRE(vec.Size() == 0); - REQUIRE(vec.Capacity() == 32); - - for (uint32_t i = 0; i < 100; ++i) - { - vec.PushBack(i); - } - - REQUIRE(vec.Size() == 100); - - vec.Clear(); - - REQUIRE(vec.Size() == 0); - REQUIRE(vec.Capacity() == 32); - } - - SECTION("Add/Fill") - { - StableVector vec; - - REQUIRE(vec.Size() == 0); - REQUIRE(vec.Capacity() == 32); - - for (uint32_t i = 0; i < 100; ++i) - { - vec.PushBack("a"); - } - - REQUIRE(vec.Size() == 100); - - vec.Remove(56); - vec.Add("z"); - - REQUIRE(vec.Size() == 100); - REQUIRE(vec[56] == "z"); - } - - SECTION("Correct Initialization") - { - StableVector vec; - - REQUIRE(incrementCounter == 0); - REQUIRE(decrementCounter == 0); - - vec.EmplaceBack("a"); - - REQUIRE(incrementCounter == 1); - REQUIRE(decrementCounter == 0); - - vec.PushBack(TestCount("b")); - - REQUIRE(incrementCounter == 3); - REQUIRE(decrementCounter == 1); - - TestCount testClass = TestCount("c"); - vec.PushBack(std::move(testClass)); - - REQUIRE(incrementCounter == 5); - REQUIRE(decrementCounter == 1); - - vec.Clear(); - - REQUIRE(incrementCounter == 5); - REQUIRE(decrementCounter == 4); - - vec.PushBack(TestCount("d")); - - REQUIRE(incrementCounter == 7); - REQUIRE(decrementCounter == 5); - - TestCount testClass2 = TestCount("e"); - vec.PushBack(testClass2); - - REQUIRE(incrementCounter == 9); - REQUIRE(decrementCounter == 5); - } - - SECTION("Out of scope check") - { - REQUIRE(incrementCounter == 9); - REQUIRE(decrementCounter == 9); - } -} +//struct Test +//{ +// uint32_t mValue; +// Test(uint32_t value) : mValue(value) {} +// Test() : mValue(0) {} +//}; +// +//static int incrementCounter = 0; +//static int decrementCounter = 0; +// +//struct TestCount +//{ +// TestCount() : m_value("") { ++incrementCounter; } +// TestCount(const std::string& val) : m_value(val) { ++incrementCounter; } +// TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; } +// TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; } +// +// TestCount& operator=(const TestCount& other) +// { +// m_value = other.m_value; +// return *this; +// } +// +// TestCount& operator=(TestCount&& other) noexcept +// { +// m_value = std::move(other.m_value); +// return *this; +// } +// +// ~TestCount() { ++decrementCounter; } +// +// std::string m_value; +//}; +// +//TEST_CASE("ChunkVector") +//{ +// SECTION("PushBack") +// { +// StableVector vec; +// +// REQUIRE(vec.Size() == 0); +// REQUIRE(vec.Capacity() == 32); +// +// for (uint32_t i = 0; i < 100; ++i) +// { +// vec.PushBack(i); +// } +// +// REQUIRE(vec.Size() == 100); +// REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2 +// } +// +// SECTION("EmplaceBack") +// { +// StableVector vec; +// +// REQUIRE(vec.Size() == 0); +// REQUIRE(vec.Capacity() == 32); +// +// for (uint32_t i = 0; i < 100; ++i) +// { +// vec.EmplaceBack(i); +// } +// +// REQUIRE(vec.Size() == 100); +// +// for (uint32_t i = 0; i < 100; ++i) +// { +// REQUIRE(vec[i].mValue == i); +// } +// } +// +// SECTION("PopBack") +// { +// StableVector vec; +// +// REQUIRE(vec.Size() == 0); +// REQUIRE(vec.Capacity() == 32); +// +// for (uint32_t i = 0; i < 100; ++i) +// { +// vec.PushBack(i); +// } +// +// REQUIRE(vec.Size() == 100); +// +// uint64_t tempVal = vec.Capacity(); +// +// for (uint32_t i = 0; i < 50; ++i) +// { +// vec.PopBack(); +// } +// +// REQUIRE(vec.Size() == 50); +// REQUIRE(vec.Capacity() == tempVal); +// } +// +// SECTION("Clear") +// { +// StableVector vec; +// +// REQUIRE(vec.Size() == 0); +// REQUIRE(vec.Capacity() == 32); +// +// for (uint32_t i = 0; i < 100; ++i) +// { +// vec.PushBack(i); +// } +// +// REQUIRE(vec.Size() == 100); +// +// vec.Clear(); +// +// REQUIRE(vec.Size() == 0); +// REQUIRE(vec.Capacity() == 32); +// } +// +// SECTION("Add/Fill") +// { +// StableVector vec; +// +// REQUIRE(vec.Size() == 0); +// REQUIRE(vec.Capacity() == 32); +// +// for (uint32_t i = 0; i < 100; ++i) +// { +// vec.PushBack("a"); +// } +// +// REQUIRE(vec.Size() == 100); +// +// vec.Remove(56); +// REQUIRE(vec[56] == "a"); +// +// vec.Add("z"); +// +// REQUIRE(vec.Size() == 100); +// REQUIRE(vec[56] == "z"); +// } +// +// SECTION("Correct Initialization") +// { +// StableVector vec; +// +// REQUIRE(incrementCounter == 0); +// REQUIRE(decrementCounter == 0); +// +// vec.EmplaceBack("a"); +// +// REQUIRE(incrementCounter == 1); +// REQUIRE(decrementCounter == 0); +// +// vec.PushBack(TestCount("b")); +// +// REQUIRE(incrementCounter == 3); +// REQUIRE(decrementCounter == 1); +// +// TestCount testClass = TestCount("c"); +// vec.PushBack(std::move(testClass)); +// +// REQUIRE(incrementCounter == 5); +// REQUIRE(decrementCounter == 1); +// +// vec.Clear(); +// +// REQUIRE(incrementCounter == 5); +// REQUIRE(decrementCounter == 4); +// +// vec.PushBack(TestCount("d")); +// +// REQUIRE(incrementCounter == 7); +// REQUIRE(decrementCounter == 5); +// +// TestCount testClass2 = TestCount("e"); +// vec.PushBack(testClass2); +// +// REQUIRE(incrementCounter == 9); +// REQUIRE(decrementCounter == 5); +// } +// +// SECTION("Out of scope check") +// { +// REQUIRE(incrementCounter == 9); +// REQUIRE(decrementCounter == 9); +// } +//} From 7b40d001ec2578906ef09066301b6c39d4a60711 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Tue, 8 Oct 2024 07:20:41 +0300 Subject: [PATCH 08/13] stable vector fix for algorithm. Still no correct Iterator. --- .../Data/Containers/BinSearchArrayMap.hpp | 6 +- .../Data/Containers/StableVector.hpp | 104 ++++- tests/BinSearchArrayMapTest.cpp | 100 ++--- tests/StableVectorTest.cpp | 372 +++++++++--------- 4 files changed, 316 insertions(+), 266 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index 00ba69a..2a525a7 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -54,7 +54,7 @@ namespace OpenVulkano V& Get(const K key) { return FindPair(key).second; } - Pair& FindPair(const K key) + Pair& FindPair(const K key) { size_t low = 0; size_t high = m_data.size(); @@ -76,7 +76,7 @@ namespace OpenVulkano high = mid - 1; } } - + throw std::runtime_error("Key not found."); } @@ -106,7 +106,7 @@ namespace OpenVulkano return -1; } - bool Contains(const K key) const noexcept + bool Contains(const K key) noexcept { size_t low = 0; size_t high = m_data.size(); diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index f42c313..fbac15a 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -52,7 +52,7 @@ namespace OpenVulkano ~VectorChunk() { - for (size_t i = 0; i < m_size; i++) + for (size_t i = 0; i < m_capacity; i++) { if (m_occupiedIndices[i]) { @@ -65,13 +65,13 @@ namespace OpenVulkano size_t GetRealIndex(size_t reqIndex) { - if (m_gapCount == 0) + if (m_gapCount == 0 || reqIndex == 0) { return reqIndex; } size_t gapCount = 0; - for (size_t i = 0; i < reqIndex; i++) + for (size_t i = 0; i <= reqIndex; i++) { if (!m_occupiedIndices[i]) { @@ -93,6 +93,8 @@ namespace OpenVulkano return m_data[i]; } } + + throw std::out_of_range("Index out of range"); } size_t GetLastOccupiedIndex() @@ -115,8 +117,17 @@ namespace OpenVulkano public: Iterator(VectorChunk* chunk, size_t index) : m_chunk(chunk), m_index(index) {} - T& operator*() { return m_chunk->GetAlignedData(m_index); } - T* operator->() { return &m_chunk->GetAlignedData(m_index); } + T& operator*() + { + auto realIndex = m_chunk->GetRealIndex(m_index); + return m_chunk->GetAlignedData(m_index); + } + + T* operator->() + { + auto realIndex = m_chunk->GetRealIndex(m_index); + return &m_chunk->GetAlignedData(m_index); + } Iterator& operator++() { @@ -174,13 +185,30 @@ namespace OpenVulkano return m_chunk != other.m_chunk || m_index != other.m_index; } + size_t GetIndex() const { return m_index; } + size_t GetChunk() const { return m_chunk; } + protected: void MoveToNextChunk() { - while (m_chunk && m_index > m_chunk->m_size) + while (m_chunk && (m_index > m_chunk->m_size || !m_chunk->m_occupiedIndices[m_index])) + { + if (m_index >= m_chunk->m_size) + { + m_chunk = m_chunk->m_next; + m_index = 0; + } + else + { + ++m_index; + } + } + + if (m_chunk && m_index >= m_chunk->m_size) { - m_index -= m_chunk->m_size; m_chunk = m_chunk->m_next; + m_index = 0; + MoveToNextChunk(); } } @@ -264,10 +292,9 @@ namespace OpenVulkano VectorChunk* currentChunk = m_FirstChunk; while (currentChunk) { - VectorChunk* nextChunk = currentChunk->m_next; - currentChunk->~VectorChunk(); - ::operator delete(currentChunk); - currentChunk = nextChunk; + VectorChunk* temp = currentChunk; + currentChunk = currentChunk->m_next; + delete temp; } } @@ -276,6 +303,7 @@ namespace OpenVulkano if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) { VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); + m_Capacity += m_LastChunk->m_capacity * GROW_FACTOR; m_LastChunk->m_next = newChunk; newChunk->m_prev = m_LastChunk; m_LastChunk = newChunk; @@ -296,6 +324,7 @@ namespace OpenVulkano if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) { VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); + m_Capacity += m_LastChunk->m_capacity * GROW_FACTOR; m_LastChunk->m_next = newChunk; newChunk->m_prev = m_LastChunk; m_LastChunk = newChunk; @@ -358,6 +387,8 @@ namespace OpenVulkano } } } + + currentChunk = currentChunk->m_next; } PushBack(std::move(value)); @@ -368,6 +399,7 @@ namespace OpenVulkano if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) { VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); + m_Capacity += m_LastChunk->m_capacity * GROW_FACTOR; m_LastChunk->m_next = newChunk; newChunk->m_prev = m_LastChunk; m_LastChunk = newChunk; @@ -404,6 +436,8 @@ namespace OpenVulkano } } } + + currentChunk = currentChunk->m_next; } EmplaceBack(std::forward(args)...); @@ -416,6 +450,15 @@ namespace OpenVulkano return; // return? or make } + if (m_LastChunk->m_nextIndex == -1) + { + VectorChunk* temp = m_LastChunk; + m_LastChunk = m_LastChunk->m_prev; + m_LastChunk->m_next = nullptr; + temp->~VectorChunk(); + ::operator delete(temp); + } + m_LastChunk->m_data[m_LastChunk->m_nextIndex - 1].~T(); m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex - 1] = false; m_LastChunk->m_nextIndex--; @@ -480,9 +523,9 @@ namespace OpenVulkano VectorChunk* currentChunk = m_FirstChunk; while (currentChunk) { - if (index + currentChunk->m_size > it.m_index) + if (index + currentChunk->m_size > it.GetIndex()) { - size_t realIndex = currentChunk->GetRealIndex(it.m_index); + size_t realIndex = currentChunk->GetRealIndex(it.GetIndex()); currentChunk->m_data[realIndex].~T(); currentChunk->m_occupiedIndices[realIndex] = false; currentChunk->m_size--; @@ -496,7 +539,7 @@ namespace OpenVulkano } } - T& operator[](size_t index) { return At(index); } + T& operator[](size_t index) noexcept { return At(index); } T& At(size_t index) { if (index >= m_Size) [[unlikely]] @@ -508,6 +551,39 @@ namespace OpenVulkano return handle.first->GetAlignedData(handle.second); } + bool Contains(size_t index) noexcept + { + if (index >= m_Size) + { + return false; + } + + auto handle = FindChunk(index); + return handle.first->m_occupiedIndices[handle.second]; + } + + /// std version of contains + bool contains(size_t index) noexcept { return Contains(index); } + + void Clear() + { + VectorChunk* currentChunk = m_FirstChunk; + while (currentChunk) + { + VectorChunk* nextChunk = currentChunk->m_next; + delete currentChunk; + currentChunk = nextChunk; + } + + m_FirstChunk = Grow(DEFAULT_CHUNK_SIZE); + m_LastChunk = m_FirstChunk; + m_Capacity = DEFAULT_CHUNK_SIZE; + m_Size = 0; + } + + /// std version of clear + void clear() { Clear(); } + /// std version of at T& at(size_t index) { return At(index); } diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp index 64813df..2df828d 100644 --- a/tests/BinSearchArrayMapTest.cpp +++ b/tests/BinSearchArrayMapTest.cpp @@ -45,69 +45,43 @@ TEST_CASE("BinSearchArrayMap With Default") map.Remove(16); map.Remove(23); map.Remove(48); - - REQUIRE(map[49] == "49"); - - printf("ARRAY WITH DEFAULT\n"); - for (int i = 0; i < 50; i++) - { - if (map.Contains(i)) - { - printf("index: %d, value: %s\n", i, map[i].c_str()); - } - else - { - printf("index: %d, value: %s\n", i, "EMPTY"); - } - } } } -//TEST_CASE("BinSearchArrayMap With StableVector") -//{ -// SECTION("Insert") -// { -// BinSearchArrayMap map; -// -// for (int i = 0; i < 50; i++) -// { -// map.Insert(i, std::to_string(i)); -// } -// -// REQUIRE(map.Size() == 50); -// REQUIRE(map.Get(16) == "16"); -// REQUIRE(map.Get(23) == "23"); -// REQUIRE(map.Get(48) == "48"); -// } -// -// SECTION("Remove") -// { -// BinSearchArrayMap map; -// -// for (int i = 0; i < 50; i++) -// { -// map.Insert(i, std::to_string(i)); -// } -// -// map.Remove(16); -// map.Remove(23); -// -// if (map.Contains(49)) -// { -// printf("index: %d, value: %s\n", 49, map[49].c_str()); -// } -// -// printf("ARRAY WITH STABLE VECTOR\n"); -// for (int i = 0; i < 50; i++) -// { -// if (map.Contains(i)) -// { -// printf("index: %d, value: %s\n", i, map[i].c_str()); -// } -// else -// { -// printf("index: %d, value: %s\n", i, "EMPTY"); -// } -// } -// } -//} \ No newline at end of file +TEST_CASE("BinSearchArrayMap With StableVector") +{ + SECTION("Insert") + { + BinSearchArrayMap map; + + for (int i = 0; i < 50; i++) + { + map.Insert(i, std::to_string(i)); + } + + REQUIRE(map.Size() == 50); + REQUIRE(map.Get(16) == "16"); + REQUIRE(map.Get(23) == "23"); + REQUIRE(map.Get(48) == "48"); + } + + SECTION("Remove") + { + BinSearchArrayMap map; + + for (int i = 0; i < 50; i++) + { + map.Insert(i, std::to_string(i)); + } + + map.Remove(16); + map.Remove(23); + map.Remove(48); + + printf("ARRAY WITH STABLE VECTOR\n"); + for (int i = 0; i < 50; i++) + { + printf("index: %d, value: %s\n", i, map[i].c_str()); + } + } +} \ No newline at end of file diff --git a/tests/StableVectorTest.cpp b/tests/StableVectorTest.cpp index 0cdb5f2..d0efb35 100644 --- a/tests/StableVectorTest.cpp +++ b/tests/StableVectorTest.cpp @@ -4,189 +4,189 @@ using namespace OpenVulkano; -//struct Test -//{ -// uint32_t mValue; -// Test(uint32_t value) : mValue(value) {} -// Test() : mValue(0) {} -//}; -// -//static int incrementCounter = 0; -//static int decrementCounter = 0; -// -//struct TestCount -//{ -// TestCount() : m_value("") { ++incrementCounter; } -// TestCount(const std::string& val) : m_value(val) { ++incrementCounter; } -// TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; } -// TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; } -// -// TestCount& operator=(const TestCount& other) -// { -// m_value = other.m_value; -// return *this; -// } -// -// TestCount& operator=(TestCount&& other) noexcept -// { -// m_value = std::move(other.m_value); -// return *this; -// } -// -// ~TestCount() { ++decrementCounter; } -// -// std::string m_value; -//}; -// -//TEST_CASE("ChunkVector") -//{ -// SECTION("PushBack") -// { -// StableVector vec; -// -// REQUIRE(vec.Size() == 0); -// REQUIRE(vec.Capacity() == 32); -// -// for (uint32_t i = 0; i < 100; ++i) -// { -// vec.PushBack(i); -// } -// -// REQUIRE(vec.Size() == 100); -// REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2 -// } -// -// SECTION("EmplaceBack") -// { -// StableVector vec; -// -// REQUIRE(vec.Size() == 0); -// REQUIRE(vec.Capacity() == 32); -// -// for (uint32_t i = 0; i < 100; ++i) -// { -// vec.EmplaceBack(i); -// } -// -// REQUIRE(vec.Size() == 100); -// -// for (uint32_t i = 0; i < 100; ++i) -// { -// REQUIRE(vec[i].mValue == i); -// } -// } -// -// SECTION("PopBack") -// { -// StableVector vec; -// -// REQUIRE(vec.Size() == 0); -// REQUIRE(vec.Capacity() == 32); -// -// for (uint32_t i = 0; i < 100; ++i) -// { -// vec.PushBack(i); -// } -// -// REQUIRE(vec.Size() == 100); -// -// uint64_t tempVal = vec.Capacity(); -// -// for (uint32_t i = 0; i < 50; ++i) -// { -// vec.PopBack(); -// } -// -// REQUIRE(vec.Size() == 50); -// REQUIRE(vec.Capacity() == tempVal); -// } -// -// SECTION("Clear") -// { -// StableVector vec; -// -// REQUIRE(vec.Size() == 0); -// REQUIRE(vec.Capacity() == 32); -// -// for (uint32_t i = 0; i < 100; ++i) -// { -// vec.PushBack(i); -// } -// -// REQUIRE(vec.Size() == 100); -// -// vec.Clear(); -// -// REQUIRE(vec.Size() == 0); -// REQUIRE(vec.Capacity() == 32); -// } -// -// SECTION("Add/Fill") -// { -// StableVector vec; -// -// REQUIRE(vec.Size() == 0); -// REQUIRE(vec.Capacity() == 32); -// -// for (uint32_t i = 0; i < 100; ++i) -// { -// vec.PushBack("a"); -// } -// -// REQUIRE(vec.Size() == 100); -// -// vec.Remove(56); -// REQUIRE(vec[56] == "a"); -// -// vec.Add("z"); -// -// REQUIRE(vec.Size() == 100); -// REQUIRE(vec[56] == "z"); -// } -// -// SECTION("Correct Initialization") -// { -// StableVector vec; -// -// REQUIRE(incrementCounter == 0); -// REQUIRE(decrementCounter == 0); -// -// vec.EmplaceBack("a"); -// -// REQUIRE(incrementCounter == 1); -// REQUIRE(decrementCounter == 0); -// -// vec.PushBack(TestCount("b")); -// -// REQUIRE(incrementCounter == 3); -// REQUIRE(decrementCounter == 1); -// -// TestCount testClass = TestCount("c"); -// vec.PushBack(std::move(testClass)); -// -// REQUIRE(incrementCounter == 5); -// REQUIRE(decrementCounter == 1); -// -// vec.Clear(); -// -// REQUIRE(incrementCounter == 5); -// REQUIRE(decrementCounter == 4); -// -// vec.PushBack(TestCount("d")); -// -// REQUIRE(incrementCounter == 7); -// REQUIRE(decrementCounter == 5); -// -// TestCount testClass2 = TestCount("e"); -// vec.PushBack(testClass2); -// -// REQUIRE(incrementCounter == 9); -// REQUIRE(decrementCounter == 5); -// } -// -// SECTION("Out of scope check") -// { -// REQUIRE(incrementCounter == 9); -// REQUIRE(decrementCounter == 9); -// } -//} +struct Test +{ + uint32_t mValue; + Test(uint32_t value) : mValue(value) {} + Test() : mValue(0) {} +}; + +static int incrementCounter = 0; +static int decrementCounter = 0; + +struct TestCount +{ + TestCount() : m_value("") { ++incrementCounter; } + TestCount(const std::string& val) : m_value(val) { ++incrementCounter; } + TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; } + TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; } + + TestCount& operator=(const TestCount& other) + { + m_value = other.m_value; + return *this; + } + + TestCount& operator=(TestCount&& other) noexcept + { + m_value = std::move(other.m_value); + return *this; + } + + ~TestCount() { ++decrementCounter; } + + std::string m_value; +}; + +TEST_CASE("ChunkVector") +{ + SECTION("PushBack") + { + StableVector vec; + + REQUIRE(vec.Size() == 0); + REQUIRE(vec.Capacity() == 32); + + for (uint32_t i = 0; i < 100; ++i) + { + vec.PushBack(i); + } + + REQUIRE(vec.Size() == 100); + REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2 + } + + SECTION("EmplaceBack") + { + StableVector vec; + + REQUIRE(vec.Size() == 0); + REQUIRE(vec.Capacity() == 32); + + for (uint32_t i = 0; i < 100; ++i) + { + vec.EmplaceBack(i); + } + + REQUIRE(vec.Size() == 100); + + for (uint32_t i = 0; i < 100; ++i) + { + REQUIRE(vec[i].mValue == i); + } + } + + SECTION("PopBack") + { + StableVector vec; + + REQUIRE(vec.Size() == 0); + REQUIRE(vec.Capacity() == 32); + + for (uint32_t i = 0; i < 100; ++i) + { + vec.PushBack(i); + } + + REQUIRE(vec.Size() == 100); + + uint64_t tempVal = vec.Capacity(); + + for (uint32_t i = 0; i < 50; ++i) + { + vec.PopBack(); + } + + REQUIRE(vec.Size() == 50); + REQUIRE(vec.Capacity() == tempVal); + } + + SECTION("Clear") + { + StableVector vec; + + REQUIRE(vec.Size() == 0); + REQUIRE(vec.Capacity() == 32); + + for (uint32_t i = 0; i < 100; ++i) + { + vec.PushBack(i); + } + + REQUIRE(vec.Size() == 100); + + vec.Clear(); + + REQUIRE(vec.Size() == 0); + REQUIRE(vec.Capacity() == 32); + } + + SECTION("Add/Fill") + { + StableVector vec; + + REQUIRE(vec.Size() == 0); + REQUIRE(vec.Capacity() == 32); + + for (uint32_t i = 0; i < 100; ++i) + { + vec.PushBack("a"); + } + + REQUIRE(vec.Size() == 100); + + vec.Remove(56); + REQUIRE(vec[56] == "a"); + + vec.Push("z"); + + REQUIRE(vec.Size() == 100); + REQUIRE(vec[56] == "z"); + } + + SECTION("Correct Initialization") + { + StableVector vec; + + REQUIRE(incrementCounter == 0); + REQUIRE(decrementCounter == 0); + + vec.EmplaceBack("a"); + + REQUIRE(incrementCounter == 1); + REQUIRE(decrementCounter == 0); + + vec.PushBack(TestCount("b")); + + REQUIRE(incrementCounter == 3); + REQUIRE(decrementCounter == 1); + + TestCount testClass = TestCount("c"); + vec.PushBack(std::move(testClass)); + + REQUIRE(incrementCounter == 5); + REQUIRE(decrementCounter == 1); + + vec.Clear(); + + REQUIRE(incrementCounter == 5); + REQUIRE(decrementCounter == 4); + + vec.PushBack(TestCount("d")); + + REQUIRE(incrementCounter == 7); + REQUIRE(decrementCounter == 5); + + TestCount testClass2 = TestCount("e"); + vec.PushBack(testClass2); + + REQUIRE(incrementCounter == 9); + REQUIRE(decrementCounter == 5); + } + + SECTION("Out of scope check") + { + REQUIRE(incrementCounter == 9); + REQUIRE(decrementCounter == 9); + } +} From 6f981682f8030de6776556a5d54cf5d33e467c2d Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Tue, 8 Oct 2024 11:15:31 +0300 Subject: [PATCH 09/13] StableVector review fix. No working iterators. --- .../Data/Containers/StableVector.hpp | 300 ++++++++---------- tests/BinSearchArrayMapTest.cpp | 59 +++- 2 files changed, 173 insertions(+), 186 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index fbac15a..fe9255f 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -191,7 +191,7 @@ namespace OpenVulkano protected: void MoveToNextChunk() { - while (m_chunk && (m_index > m_chunk->m_size || !m_chunk->m_occupiedIndices[m_index])) + while (m_chunk && !m_chunk->m_occupiedIndices[m_index]) { if (m_index >= m_chunk->m_size) { @@ -204,11 +204,10 @@ namespace OpenVulkano } } - if (m_chunk && m_index >= m_chunk->m_size) + if (m_chunk && m_index > m_chunk->m_size) { m_chunk = m_chunk->m_next; m_index = 0; - MoveToNextChunk(); } } @@ -220,26 +219,26 @@ namespace OpenVulkano }; public: - StableVector() : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + StableVector() : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_FirstChunk = Grow(DEFAULT_CHUNK_SIZE); - m_LastChunk = m_FirstChunk; - m_Capacity = DEFAULT_CHUNK_SIZE; + m_firstChunk = Grow(DEFAULT_CHUNK_SIZE); + m_lastChunk = m_firstChunk; + m_capacity = DEFAULT_CHUNK_SIZE; } - StableVector(size_t size) : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + StableVector(size_t size) : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_FirstChunk = Grow(size); - m_LastChunk = m_FirstChunk; - m_Capacity = size; + m_firstChunk = Grow(size); + m_lastChunk = m_firstChunk; + m_capacity = size; } StableVector(size_t size, const T& value) - : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_FirstChunk = Grow(size); - m_LastChunk = m_FirstChunk; - m_Capacity = size; + m_firstChunk = Grow(size); + m_lastChunk = m_firstChunk; + m_capacity = size; for (size_t i = 0; i < size; i++) { @@ -248,11 +247,11 @@ namespace OpenVulkano } StableVector(std::initializer_list list) - : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_FirstChunk = Grow(list.size()); - m_LastChunk = m_FirstChunk; - m_Capacity = list.size(); + m_firstChunk = Grow(list.size()); + m_lastChunk = m_firstChunk; + m_capacity = list.size(); for (const T& value: list) { @@ -261,11 +260,11 @@ namespace OpenVulkano } StableVector(const StableVector& copy) - : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_FirstChunk = Grow(copy.m_Capacity); // One big chunk to make Stable contiguous. - m_LastChunk = m_FirstChunk; - m_Capacity = copy.m_Capacity; + m_firstChunk = Grow(copy.m_capacity); // One big chunk to make Stable contiguous. + m_lastChunk = m_firstChunk; + m_capacity = copy.m_capacity; for (size_t i = 0; i < copy.Size(); i++) { @@ -274,22 +273,22 @@ namespace OpenVulkano } StableVector(StableVector&& move) noexcept - : m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0) + : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_FirstChunk = move.m_FirstChunk; - m_LastChunk = move.m_LastChunk; - m_Size = move.m_Size; - m_Capacity = move.m_Capacity; + m_firstChunk = move.m_firstChunk; + m_lastChunk = move.m_lastChunk; + m_size = move.m_size; + m_capacity = move.m_capacity; - move.m_FirstChunk = nullptr; - move.m_LastChunk = nullptr; - move.m_Size = 0; - move.m_Capacity = 0; + move.m_firstChunk = nullptr; + move.m_lastChunk = nullptr; + move.m_size = 0; + move.m_capacity = 0; } ~StableVector() { - VectorChunk* currentChunk = m_FirstChunk; + VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { VectorChunk* temp = currentChunk; @@ -300,50 +299,44 @@ namespace OpenVulkano void PushBack(const T& value) { - if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) + if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) { - VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); - m_Capacity += m_LastChunk->m_capacity * GROW_FACTOR; - m_LastChunk->m_next = newChunk; - newChunk->m_prev = m_LastChunk; - m_LastChunk = newChunk; + VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); + m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; + m_lastChunk->m_next = newChunk; + newChunk->m_prev = m_lastChunk; + m_lastChunk = newChunk; } - new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(value); - m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true; - m_LastChunk->m_nextIndex++; - m_LastChunk->m_size++; - m_Size++; + new (&m_lastChunk->m_data[m_lastChunk->m_nextIndex]) T(value); + m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; + m_lastChunk->m_nextIndex++; + m_lastChunk->m_size++; + m_size++; } - /// std version of push_back(const T& value) - void push_back(const T& value) { PushBack(value); } - void PushBack(T&& value) noexcept { - if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) + if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) { - VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); - m_Capacity += m_LastChunk->m_capacity * GROW_FACTOR; - m_LastChunk->m_next = newChunk; - newChunk->m_prev = m_LastChunk; - m_LastChunk = newChunk; + VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); + m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; + m_lastChunk->m_next = newChunk; + newChunk->m_prev = m_lastChunk; + m_lastChunk = newChunk; } - new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(std::move(value)); - m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true; - m_LastChunk->m_nextIndex++; - m_LastChunk->m_size++; - m_Size++; + new (&m_lastChunk->m_data[m_lastChunk->m_nextIndex]) T(std::move(value)); + m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; + m_lastChunk->m_nextIndex++; + m_lastChunk->m_size++; + m_size++; } - /// std version of push_back(T&& value) - void push_back(T&& value) { PushBack(value); } - // Checks the first available gap and inserts. If no gap it works like push_back(const T& value) void Push(const T& value) { - VectorChunk* currentChunk = m_FirstChunk; + VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap @@ -356,7 +349,7 @@ namespace OpenVulkano currentChunk->m_occupiedIndices[i] = true; currentChunk->m_size++; currentChunk->m_gapCount--; - m_Size++; + m_size++; return; } } @@ -369,7 +362,7 @@ namespace OpenVulkano // Checks the first available gap and inserts. If no gap it works like push_back(T&& value) void Push(T&& value) noexcept { - VectorChunk* currentChunk = m_FirstChunk; + VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap @@ -382,7 +375,7 @@ namespace OpenVulkano currentChunk->m_occupiedIndices[i] = true; currentChunk->m_size++; currentChunk->m_gapCount--; - m_Size++; + m_size++; return; } } @@ -396,29 +389,26 @@ namespace OpenVulkano template void EmplaceBack(Args&&... args) { - if (m_LastChunk->m_nextIndex == m_LastChunk->m_capacity) + if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) { - VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR); - m_Capacity += m_LastChunk->m_capacity * GROW_FACTOR; - m_LastChunk->m_next = newChunk; - newChunk->m_prev = m_LastChunk; - m_LastChunk = newChunk; + VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); + m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; + m_lastChunk->m_next = newChunk; + newChunk->m_prev = m_lastChunk; + m_lastChunk = newChunk; } - new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(std::forward(args)...); - m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true; - m_LastChunk->m_nextIndex++; - m_LastChunk->m_size++; - m_Size++; + new (&m_lastChunk->m_data[m_lastChunk->m_nextIndex]) T(std::forward(args)...); + m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; + m_lastChunk->m_nextIndex++; + m_lastChunk->m_size++; + m_size++; } - /// std version of emplace_back - template void emplace_back(Args&&... args) { EmplaceBack(std::forward(args)...); } - // Checks the first available gap and inserts. If no gap it works like emplace_back(Args&&... args) template void Emplace(Args&&... args) { - VectorChunk* currentChunk = m_FirstChunk; + VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap @@ -431,7 +421,7 @@ namespace OpenVulkano currentChunk->m_occupiedIndices[i] = true; currentChunk->m_size++; currentChunk->m_gapCount--; - m_Size++; + m_size++; return; } } @@ -445,56 +435,47 @@ namespace OpenVulkano void PopBack() { - if (m_Size == 0) + if (m_size == 0) { return; // return? or make } - if (m_LastChunk->m_nextIndex == -1) + if (m_lastChunk->m_nextIndex == -1) { - VectorChunk* temp = m_LastChunk; - m_LastChunk = m_LastChunk->m_prev; - m_LastChunk->m_next = nullptr; + VectorChunk* temp = m_lastChunk; + m_lastChunk = m_lastChunk->m_prev; + m_lastChunk->m_next = nullptr; temp->~VectorChunk(); ::operator delete(temp); } - m_LastChunk->m_data[m_LastChunk->m_nextIndex - 1].~T(); - m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex - 1] = false; - m_LastChunk->m_nextIndex--; - m_LastChunk->m_size--; - m_Size--; + m_lastChunk->m_data[m_lastChunk->m_nextIndex - 1].~T(); + m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex - 1] = false; + m_lastChunk->m_nextIndex--; + m_lastChunk->m_size--; + m_size--; } - /// std version of pop_back - void pop_back() { PopBack(); } - constexpr T& Back() const { - if (m_Size == 0) + if (m_size == 0) { throw std::out_of_range("Index out of range"); } - return m_LastChunk->m_data[m_LastChunk->GetLastOccupiedIndex()]; + return m_lastChunk->m_data[m_lastChunk->GetLastOccupiedIndex()]; } - /// std version of back - constexpr T& back() const { return Back(); } - constexpr T& Front() const { - if (m_Size == 0) + if (m_size == 0) { throw std::out_of_range("Index out of range"); } - return m_FirstChunk->m_data[0]; + return m_firstChunk->m_data[0]; } - /// std version of front - constexpr T& front() const { return Front(); } - void Remove(size_t index) { auto handle = FindChunk(index); @@ -513,61 +494,30 @@ namespace OpenVulkano handle.first->m_occupiedIndices[realIndex] = false; handle.first->m_size--; handle.first->m_gapCount++; - m_Size--; + m_size--; } - // Temporary non correct solution. (DONT MIND THIS ERASE) - void erase(Iterator it) + void Remove(const Iterator& it) { Remove(it.GetIndex()); } + + T& operator[](size_t index) noexcept { - size_t index = 0; - VectorChunk* currentChunk = m_FirstChunk; - while (currentChunk) - { - if (index + currentChunk->m_size > it.GetIndex()) - { - size_t realIndex = currentChunk->GetRealIndex(it.GetIndex()); - currentChunk->m_data[realIndex].~T(); - currentChunk->m_occupiedIndices[realIndex] = false; - currentChunk->m_size--; - currentChunk->m_gapCount++; - m_Size--; - return; - } - - index += currentChunk->m_size; - currentChunk = currentChunk->m_next; - } - } - - T& operator[](size_t index) noexcept { return At(index); } - T& At(size_t index) - { - if (index >= m_Size) [[unlikely]] - { - throw std::out_of_range("Index out of range"); - } - auto handle = FindChunk(index); return handle.first->GetAlignedData(handle.second); } - bool Contains(size_t index) noexcept + T& At(size_t index) { - if (index >= m_Size) + if (index >= m_size) [[unlikely]] { - return false; + throw std::out_of_range("Index out of range"); } - auto handle = FindChunk(index); - return handle.first->m_occupiedIndices[handle.second]; + return operator[](index); } - /// std version of contains - bool contains(size_t index) noexcept { return Contains(index); } - void Clear() { - VectorChunk* currentChunk = m_FirstChunk; + VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { VectorChunk* nextChunk = currentChunk->m_next; @@ -575,35 +525,37 @@ namespace OpenVulkano currentChunk = nextChunk; } - m_FirstChunk = Grow(DEFAULT_CHUNK_SIZE); - m_LastChunk = m_FirstChunk; - m_Capacity = DEFAULT_CHUNK_SIZE; - m_Size = 0; + m_firstChunk = Grow(DEFAULT_CHUNK_SIZE); + m_lastChunk = m_firstChunk; + m_capacity = DEFAULT_CHUNK_SIZE; + m_size = 0; } /// std version of clear + + size_t Size() const noexcept { return m_size; } + size_t Capacity() const noexcept { return m_capacity; } + bool Empty() const noexcept { return m_size == 0; } + + Iterator begin() { return Iterator(m_firstChunk, 0); } + Iterator end() { return Iterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); } + + const Iterator& cbegin() { return Iterator(m_firstChunk, 0); } + const Iterator& cend() { return Iterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); } + + //region std aliases + void push_back(const T& value) { PushBack(value); } + void push_back(T&& value) { PushBack(std::move(value)); } + template void emplace_back(Args&&... args) { EmplaceBack(std::forward(args)...); } + void pop_back() { PopBack(); } + T& back() { return Back(); } + T& front() { return Front(); } + bool empty() const noexcept { return Empty(); } void clear() { Clear(); } - - /// std version of at - T& at(size_t index) { return At(index); } - - size_t Size() const noexcept { return m_Size; } - /// std version of size - size_t size() const noexcept { return m_Size; } - - size_t Capacity() const noexcept { return m_Capacity; } - /// std version of capacity - size_t capacity() const noexcept { return m_Capacity; } - - bool Empty() const noexcept { return m_Size == 0; } - /// std version of empty - bool empty() const noexcept { return m_Size == 0; } - - Iterator begin() { return Iterator(m_FirstChunk, 0); } - Iterator end() { return Iterator(m_LastChunk, m_LastChunk->m_nextIndex - 1); } - - const Iterator& cbegin() { return Iterator(m_FirstChunk, 0); } - const Iterator& cend() { return Iterator(m_LastChunk, m_LastChunk->m_nextIndex - 1); } + void erase(const Iterator& it) { Remove(it.GetIndex()); } + size_t size() const noexcept { return Size(); } + size_t capacity() const noexcept { return Capacity(); } + //endregion protected: VectorChunk* Grow(size_t requestSize) @@ -618,7 +570,7 @@ namespace OpenVulkano std::pair FindChunk(size_t index) { size_t leftIndex = index; - VectorChunk* currentChunk = m_FirstChunk; + VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { if (leftIndex < currentChunk->m_size) @@ -634,10 +586,10 @@ namespace OpenVulkano } private: - VectorChunk* m_FirstChunk; - VectorChunk* m_LastChunk; - size_t m_Size; - size_t m_Capacity; + VectorChunk* m_firstChunk; + VectorChunk* m_lastChunk; + size_t m_size; + size_t m_capacity; }; } diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp index 2df828d..f69ecfa 100644 --- a/tests/BinSearchArrayMapTest.cpp +++ b/tests/BinSearchArrayMapTest.cpp @@ -45,18 +45,17 @@ TEST_CASE("BinSearchArrayMap With Default") map.Remove(16); map.Remove(23); map.Remove(48); - } -} -TEST_CASE("BinSearchArrayMap With StableVector") -{ - SECTION("Insert") + REQUIRE(map.Size() == 47); + } + + SECTION("Emplace") { - BinSearchArrayMap map; + BinSearchArrayMap map; for (int i = 0; i < 50; i++) { - map.Insert(i, std::to_string(i)); + map.Emplace(i, std::to_string(i)); } REQUIRE(map.Size() == 50); @@ -65,7 +64,39 @@ TEST_CASE("BinSearchArrayMap With StableVector") REQUIRE(map.Get(48) == "48"); } - SECTION("Remove") + SECTION("FindPair") + { + BinSearchArrayMap map; + + for (int i = 0; i < 50; i++) + { + map.Insert(i, std::to_string(i)); + } + + auto pair = map.FindPair(16); + REQUIRE(pair.first == 16); + REQUIRE(pair.second == "16"); + } +} + +TEST_CASE("BinSearchArrayMap With StableVector") +{ + //SECTION("Insert") + //{ + // BinSearchArrayMap map; + + // for (int i = 0; i < 50; i++) + // { + // map.Insert(i, std::to_string(i)); + // } + + // REQUIRE(map.Size() == 50); + // REQUIRE(map.Get(16) == "16"); + // REQUIRE(map.Get(23) == "23"); + // REQUIRE(map.Get(48) == "48"); + //} + + /*SECTION("Remove") { BinSearchArrayMap map; @@ -78,10 +109,14 @@ TEST_CASE("BinSearchArrayMap With StableVector") map.Remove(23); map.Remove(48); - printf("ARRAY WITH STABLE VECTOR\n"); - for (int i = 0; i < 50; i++) + for (int i = 0; i < map.Size(); i++) { - printf("index: %d, value: %s\n", i, map[i].c_str()); + if (i == 16 || i == 23 || i == 48) + { + continue; + } + + printf("i: %d, value: %s\n", i, map[i].c_str()); } - } + }*/ } \ No newline at end of file From 0e34b90f670c28af4f29b10a5c368cf35905479e Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Wed, 9 Oct 2024 18:20:41 +0300 Subject: [PATCH 10/13] Stable Vector fully works as both Standalone and with BinSearchArrayMap DONE --- .../Data/Containers/BinSearchArrayMap.hpp | 50 ++------------- .../Data/Containers/StableVector.hpp | 61 +++++++++---------- tests/BinSearchArrayMapTest.cpp | 55 +++++++++++------ 3 files changed, 70 insertions(+), 96 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index 2a525a7..d6ff994 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -56,28 +56,12 @@ namespace OpenVulkano Pair& FindPair(const K key) { - size_t low = 0; - size_t high = m_data.size(); - - while (low <= high) + std::streamsize index = FindIndexInVector(key); + if (index < 0) { - size_t mid = low + (high - low) / 2; - - if (m_data[mid].first == key) - { - return m_data[mid]; - } - else if (m_data[mid].first < key) - { - low = mid + 1; - } - else - { - high = mid - 1; - } + std::runtime_error("Key not found"); } - - throw std::runtime_error("Key not found."); + return m_data[index]; } std::streamsize FindIndexInVector(const K key) @@ -106,31 +90,7 @@ namespace OpenVulkano return -1; } - bool Contains(const K key) noexcept - { - size_t low = 0; - size_t high = m_data.size(); - - while (low <= high) - { - size_t mid = low + (high - low) / 2; - - if (m_data[mid].first == key) - { - return true; - } - else if (m_data[mid].first < key) - { - low = mid + 1; - } - else - { - high = mid - 1; - } - } - - return false; - } + bool Contains(const K key) noexcept { return FindIndexInVector(key) >= 0; } void Clear() { m_data.clear(); } diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index fe9255f..0957deb 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -120,14 +120,10 @@ namespace OpenVulkano T& operator*() { auto realIndex = m_chunk->GetRealIndex(m_index); - return m_chunk->GetAlignedData(m_index); + return m_chunk->GetAlignedData(realIndex); } - T* operator->() - { - auto realIndex = m_chunk->GetRealIndex(m_index); - return &m_chunk->GetAlignedData(m_index); - } + T* operator->() { return &operator*(); } Iterator& operator++() { @@ -139,8 +135,7 @@ namespace OpenVulkano Iterator operator++(int) { Iterator temp = *this; - ++m_index; - MoveToNextChunk(); + ++temp; return temp; } @@ -154,8 +149,7 @@ namespace OpenVulkano Iterator operator--(int) { Iterator temp = *this; - --m_index; - MoveToPrevChunk(); + --temp; return temp; } @@ -185,37 +179,31 @@ namespace OpenVulkano return m_chunk != other.m_chunk || m_index != other.m_index; } - size_t GetIndex() const { return m_index; } - size_t GetChunk() const { return m_chunk; } + std::streamsize GetIndex() const { return m_chunk->GetRealIndex(m_index); } + VectorChunk* GetChunk() const { return m_chunk; } protected: void MoveToNextChunk() { - while (m_chunk && !m_chunk->m_occupiedIndices[m_index]) - { - if (m_index >= m_chunk->m_size) - { - m_chunk = m_chunk->m_next; - m_index = 0; - } - else - { - ++m_index; - } - } - - if (m_chunk && m_index > m_chunk->m_size) + while (m_chunk && m_index >= m_chunk->m_size) { + m_index -= m_chunk->m_size; m_chunk = m_chunk->m_next; - m_index = 0; } } - void MoveToPrevChunk() {} + void MoveToPrevChunk() + { + while (m_chunk && m_index < 0) + { + m_index += m_chunk->m_size; + m_chunk = m_chunk->m_prev; + } + } private: VectorChunk* m_chunk; - size_t m_index; + std::streamsize m_index; }; public: @@ -354,6 +342,8 @@ namespace OpenVulkano } } } + + currentChunk = currentChunk->m_next; } PushBack(value); @@ -497,7 +487,14 @@ namespace OpenVulkano m_size--; } - void Remove(const Iterator& it) { Remove(it.GetIndex()); } + void Remove(const Iterator& it) + { + it.GetChunk()->m_data[it.GetIndex()].~T(); + it.GetChunk()->m_occupiedIndices[it.GetIndex()] = false; + it.GetChunk()->m_size--; + it.GetChunk()->m_gapCount++; + m_size--; + } T& operator[](size_t index) noexcept { @@ -531,8 +528,6 @@ namespace OpenVulkano m_size = 0; } - /// std version of clear - size_t Size() const noexcept { return m_size; } size_t Capacity() const noexcept { return m_capacity; } bool Empty() const noexcept { return m_size == 0; } @@ -552,7 +547,7 @@ namespace OpenVulkano T& front() { return Front(); } bool empty() const noexcept { return Empty(); } void clear() { Clear(); } - void erase(const Iterator& it) { Remove(it.GetIndex()); } + void erase(const Iterator& it) { Remove(it); } size_t size() const noexcept { return Size(); } size_t capacity() const noexcept { return Capacity(); } //endregion diff --git a/tests/BinSearchArrayMapTest.cpp b/tests/BinSearchArrayMapTest.cpp index f69ecfa..65f628e 100644 --- a/tests/BinSearchArrayMapTest.cpp +++ b/tests/BinSearchArrayMapTest.cpp @@ -47,6 +47,18 @@ TEST_CASE("BinSearchArrayMap With Default") map.Remove(48); REQUIRE(map.Size() == 47); + + for (int i = 0; i < 50; i++) + { + if (i == 16 || i == 23 || i == 48) + { + REQUIRE(!map.Contains(i)); + } + else + { + REQUIRE(map.Get(i) == std::to_string(i)); + } + } } SECTION("Emplace") @@ -81,22 +93,27 @@ TEST_CASE("BinSearchArrayMap With Default") TEST_CASE("BinSearchArrayMap With StableVector") { - //SECTION("Insert") - //{ - // BinSearchArrayMap map; + SECTION("Insert") + { + BinSearchArrayMap map; - // for (int i = 0; i < 50; i++) - // { - // map.Insert(i, std::to_string(i)); - // } + for (int i = 0; i < 50; i++) + { + map.Insert(i, std::to_string(i)); + } - // REQUIRE(map.Size() == 50); - // REQUIRE(map.Get(16) == "16"); - // REQUIRE(map.Get(23) == "23"); - // REQUIRE(map.Get(48) == "48"); - //} + REQUIRE(map.Size() == 50); + REQUIRE(map.Get(16) == "16"); + REQUIRE(map.Get(23) == "23"); + REQUIRE(map.Get(48) == "48"); - /*SECTION("Remove") + for (int i = 0; i < 50; i++) + { + REQUIRE(map.Get(i) == std::to_string(i)); + } + } + + SECTION("Remove") { BinSearchArrayMap map; @@ -109,14 +126,16 @@ TEST_CASE("BinSearchArrayMap With StableVector") map.Remove(23); map.Remove(48); - for (int i = 0; i < map.Size(); i++) + for (int i = 0; i < 50; i++) { if (i == 16 || i == 23 || i == 48) { - continue; + REQUIRE(!map.Contains(i)); + } + else + { + REQUIRE(map.Get(i) == std::to_string(i)); } - - printf("i: %d, value: %s\n", i, map[i].c_str()); } - }*/ + } } \ No newline at end of file From 89ce60f86938a74c87c3aeca34db212f3d02c77f Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Wed, 9 Oct 2024 20:17:21 +0300 Subject: [PATCH 11/13] StableVector repetition fix. --- .../Data/Containers/BinSearchArrayMap.hpp | 4 +- .../Data/Containers/StableVector.hpp | 194 +++++------------- 2 files changed, 59 insertions(+), 139 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp index d6ff994..1439fc2 100644 --- a/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp +++ b/openVulkanoCpp/Data/Containers/BinSearchArrayMap.hpp @@ -14,7 +14,7 @@ namespace OpenVulkano { template class Pair = std::pair, - template class Vec = std::vector, typename = std::enable_if_t::value>> + template class Vec = std::vector, typename = std::enable_if_t::value>> class BinSearchArrayMap { public: @@ -59,7 +59,7 @@ namespace OpenVulkano std::streamsize index = FindIndexInVector(key); if (index < 0) { - std::runtime_error("Key not found"); + throw std::runtime_error("Key not found"); } return m_data[index]; } diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index 0957deb..77662a8 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -30,7 +30,7 @@ namespace OpenVulkano * * @throw Please know that this vector creates array gaps when you remove an element. */ - template class StableVector + template class StableVector { struct VectorChunk { @@ -174,10 +174,7 @@ namespace OpenVulkano return m_chunk == other.m_chunk && m_index == other.m_index; } - bool operator!=(const Iterator& other) const - { - return m_chunk != other.m_chunk || m_index != other.m_index; - } + bool operator!=(const Iterator& other) const { return !(*this == other); } std::streamsize GetIndex() const { return m_chunk->GetRealIndex(m_index); } VectorChunk* GetChunk() const { return m_chunk; } @@ -285,143 +282,17 @@ namespace OpenVulkano } } - void PushBack(const T& value) - { - if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) - { - VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); - m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; - m_lastChunk->m_next = newChunk; - newChunk->m_prev = m_lastChunk; - m_lastChunk = newChunk; - } - - new (&m_lastChunk->m_data[m_lastChunk->m_nextIndex]) T(value); - m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; - m_lastChunk->m_nextIndex++; - m_lastChunk->m_size++; - m_size++; - } - - void PushBack(T&& value) noexcept - { - if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) - { - VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); - m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; - m_lastChunk->m_next = newChunk; - newChunk->m_prev = m_lastChunk; - m_lastChunk = newChunk; - } - - new (&m_lastChunk->m_data[m_lastChunk->m_nextIndex]) T(std::move(value)); - m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; - m_lastChunk->m_nextIndex++; - m_lastChunk->m_size++; - m_size++; - } - - // Checks the first available gap and inserts. If no gap it works like push_back(const T& value) - void Push(const T& value) - { - VectorChunk* currentChunk = m_firstChunk; - while (currentChunk) - { - if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap - { - for (size_t i = 0; i < currentChunk->m_capacity; i++) - { - if (!currentChunk->m_occupiedIndices[i]) - { - new (¤tChunk->m_data[i]) T(value); - currentChunk->m_occupiedIndices[i] = true; - currentChunk->m_size++; - currentChunk->m_gapCount--; - m_size++; - return; - } - } - } - - currentChunk = currentChunk->m_next; - } - - PushBack(value); - } - - // Checks the first available gap and inserts. If no gap it works like push_back(T&& value) - void Push(T&& value) noexcept - { - VectorChunk* currentChunk = m_firstChunk; - while (currentChunk) - { - if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap - { - for (size_t i = 0; i < currentChunk->m_capacity; i++) - { - if (!currentChunk->m_occupiedIndices[i]) - { - new (¤tChunk->m_data[i]) T(std::move(value)); - currentChunk->m_occupiedIndices[i] = true; - currentChunk->m_size++; - currentChunk->m_gapCount--; - m_size++; - return; - } - } - } - - currentChunk = currentChunk->m_next; - } - - PushBack(std::move(value)); - } + void PushBack(const T& value) { new (InsertBack()) T(value); } + void PushBack(T&& value) noexcept { new (InsertBack()) T(std::move(value)); } template void EmplaceBack(Args&&... args) { - if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) - { - VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); - m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; - m_lastChunk->m_next = newChunk; - newChunk->m_prev = m_lastChunk; - m_lastChunk = newChunk; - } - - new (&m_lastChunk->m_data[m_lastChunk->m_nextIndex]) T(std::forward(args)...); - m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; - m_lastChunk->m_nextIndex++; - m_lastChunk->m_size++; - m_size++; + new (InsertBack()) T(std::forward(args)...); } - // Checks the first available gap and inserts. If no gap it works like emplace_back(Args&&... args) - template void Emplace(Args&&... args) - { - VectorChunk* currentChunk = m_firstChunk; - while (currentChunk) - { - if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap - { - for (size_t i = 0; i < currentChunk->m_capacity; i++) - { - if (!currentChunk->m_occupiedIndices[i]) - { - new (¤tChunk->m_data[i]) T(std::forward(args)...); - currentChunk->m_occupiedIndices[i] = true; - currentChunk->m_size++; - currentChunk->m_gapCount--; - m_size++; - return; - } - } - } - - currentChunk = currentChunk->m_next; - } - - EmplaceBack(std::forward(args)...); - } + void Push(const T& value) { new (Insert()) T(value); } + void Push(T&& value) noexcept { new (Insert()) T(std::move(value)); } + template void Emplace(Args&&... args) { new (Insert()) T(std::forward(args)...); } void PopBack() { @@ -580,11 +451,60 @@ namespace OpenVulkano throw std::out_of_range("Index out of range"); } + T* InsertBack() + { + if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity) + { + VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR); + m_capacity += m_lastChunk->m_capacity * GROW_FACTOR; + m_lastChunk->m_next = newChunk; + newChunk->m_prev = m_lastChunk; + m_lastChunk = newChunk; + } + + m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true; + m_lastChunk->m_size++; + m_lastChunk->m_gapCount++; + m_size++; + return &m_lastChunk->m_data[m_lastChunk->m_nextIndex++]; + } + + T* Insert() + { + T* target = nullptr; + VectorChunk* currentChunk = m_firstChunk; + while (currentChunk) + { + if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap + { + for (size_t i = 0; i < currentChunk->m_capacity; i++) + { + if (!currentChunk->m_occupiedIndices[i]) + { + target = ¤tChunk->m_data[i]; + currentChunk->m_occupiedIndices[i] = true; + currentChunk->m_size++; + currentChunk->m_gapCount--; + m_size++; + return target; + } + } + } + + currentChunk = currentChunk->m_next; + } + + return InsertBack(); + } + private: VectorChunk* m_firstChunk; VectorChunk* m_lastChunk; size_t m_size; size_t m_capacity; + + static inline constexpr size_t DEFAULT_CHUNK_SIZE = 32; + static inline constexpr size_t GROW_FACTOR = 2; }; } From 8e527074e32bb5564fcef13dcca1374b38b6724d Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Wed, 9 Oct 2024 23:50:37 +0300 Subject: [PATCH 12/13] fixed review on stableVector. --- .../Data/Containers/StableVector.hpp | 129 ++++++++---------- 1 file changed, 56 insertions(+), 73 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index 77662a8..5533b12 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -56,6 +56,7 @@ namespace OpenVulkano { if (m_occupiedIndices[i]) { + m_occupiedIndices[i] = false; m_data[i].~T(); } } @@ -65,7 +66,7 @@ namespace OpenVulkano size_t GetRealIndex(size_t reqIndex) { - if (m_gapCount == 0 || reqIndex == 0) + if (m_gapCount == 0) { return reqIndex; } @@ -79,27 +80,7 @@ namespace OpenVulkano } } - return reqIndex + gapCount; - } - - T& GetAlignedData(size_t index) - { - size_t realIndex = GetRealIndex(index); - - for (size_t i = realIndex; i < m_capacity; i++) - { - if (m_occupiedIndices[i]) - { - return m_data[i]; - } - } - - throw std::out_of_range("Index out of range"); - } - - size_t GetLastOccupiedIndex() - { - for (size_t i = m_capacity - 1; i >= 0; i--) + for (size_t i = reqIndex + gapCount; i < m_capacity; i++) { if (m_occupiedIndices[i]) { @@ -107,20 +88,22 @@ namespace OpenVulkano } } - return 0; + return reqIndex + gapCount; } }; public: class Iterator { + friend class StableVector; + public: Iterator(VectorChunk* chunk, size_t index) : m_chunk(chunk), m_index(index) {} T& operator*() { auto realIndex = m_chunk->GetRealIndex(m_index); - return m_chunk->GetAlignedData(realIndex); + return m_chunk->m_data[realIndex]; } T* operator->() { return &operator*(); } @@ -176,10 +159,7 @@ namespace OpenVulkano bool operator!=(const Iterator& other) const { return !(*this == other); } - std::streamsize GetIndex() const { return m_chunk->GetRealIndex(m_index); } - VectorChunk* GetChunk() const { return m_chunk; } - - protected: + private: void MoveToNextChunk() { while (m_chunk && m_index >= m_chunk->m_size) @@ -198,20 +178,16 @@ namespace OpenVulkano } } + std::streamsize GetIteratorIndex() const { return m_chunk->GetRealIndex(m_index); } + private: VectorChunk* m_chunk; std::streamsize m_index; }; public: - StableVector() : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) - { - m_firstChunk = Grow(DEFAULT_CHUNK_SIZE); - m_lastChunk = m_firstChunk; - m_capacity = DEFAULT_CHUNK_SIZE; - } - - StableVector(size_t size) : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + StableVector(size_t size = DEFAULT_CHUNK_SIZE) + : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { m_firstChunk = Grow(size); m_lastChunk = m_firstChunk; @@ -219,12 +195,8 @@ namespace OpenVulkano } StableVector(size_t size, const T& value) - : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + : StableVector(size), m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_firstChunk = Grow(size); - m_lastChunk = m_firstChunk; - m_capacity = size; - for (size_t i = 0; i < size; i++) { PushBack(value); @@ -232,12 +204,8 @@ namespace OpenVulkano } StableVector(std::initializer_list list) - : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + : StableVector(list.size), m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_firstChunk = Grow(list.size()); - m_lastChunk = m_firstChunk; - m_capacity = list.size(); - for (const T& value: list) { PushBack(value); @@ -245,12 +213,8 @@ namespace OpenVulkano } StableVector(const StableVector& copy) - : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + : StableVector(copy.m_size), m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { - m_firstChunk = Grow(copy.m_capacity); // One big chunk to make Stable contiguous. - m_lastChunk = m_firstChunk; - m_capacity = copy.m_capacity; - for (size_t i = 0; i < copy.Size(); i++) { PushBack(copy.At(i)); @@ -273,12 +237,14 @@ namespace OpenVulkano ~StableVector() { + // Destroy everything left VectorChunk* currentChunk = m_firstChunk; while (currentChunk) { VectorChunk* temp = currentChunk; currentChunk = currentChunk->m_next; - delete temp; + temp->~VectorChunk(); + ::operator delete(temp); } } @@ -312,8 +278,8 @@ namespace OpenVulkano m_lastChunk->m_data[m_lastChunk->m_nextIndex - 1].~T(); m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex - 1] = false; - m_lastChunk->m_nextIndex--; m_lastChunk->m_size--; + m_lastChunk->m_gapCount++; m_size--; } @@ -324,7 +290,7 @@ namespace OpenVulkano throw std::out_of_range("Index out of range"); } - return m_lastChunk->m_data[m_lastChunk->GetLastOccupiedIndex()]; + return m_lastChunk->m_data[m_lastChunk->m_nextIndex - 1]; } constexpr T& Front() const @@ -351,26 +317,24 @@ namespace OpenVulkano throw std::out_of_range("Index out of range"); } - handle.first->m_data[realIndex].~T(); - handle.first->m_occupiedIndices[realIndex] = false; - handle.first->m_size--; - handle.first->m_gapCount++; - m_size--; + Delete(realIndex, handle.first); } void Remove(const Iterator& it) { - it.GetChunk()->m_data[it.GetIndex()].~T(); - it.GetChunk()->m_occupiedIndices[it.GetIndex()] = false; - it.GetChunk()->m_size--; - it.GetChunk()->m_gapCount++; - m_size--; + if (it.m_chunk == nullptr) + { + throw std::out_of_range("Index out of range"); + } + + Delete(it.GetIteratorIndex(), it.m_chunk); } T& operator[](size_t index) noexcept { auto handle = FindChunk(index); - return handle.first->GetAlignedData(handle.second); + size_t realIndex = handle.first->GetRealIndex(handle.second); + return handle.first->m_data[realIndex]; } T& At(size_t index) @@ -383,20 +347,30 @@ namespace OpenVulkano return operator[](index); } - void Clear() + void Clear() { - VectorChunk* currentChunk = m_firstChunk; + // Get the first chunk's cap + size_t cap = m_firstChunk->m_capacity; + + // Annihilate everything + VectorChunk* currentChunk = m_firstChunk->m_next; while (currentChunk) { - VectorChunk* nextChunk = currentChunk->m_next; - delete currentChunk; - currentChunk = nextChunk; + VectorChunk* temp = currentChunk; + currentChunk = currentChunk->m_next; + temp->~VectorChunk(); + ::operator delete(temp); } - m_firstChunk = Grow(DEFAULT_CHUNK_SIZE); + // Reset the first chunk + m_firstChunk->m_next = nullptr; m_lastChunk = m_firstChunk; - m_capacity = DEFAULT_CHUNK_SIZE; + m_firstChunk->m_size = 0; + m_firstChunk->m_nextIndex = 0; + m_firstChunk->m_gapCount = 0; + m_firstChunk->~VectorChunk(); m_size = 0; + m_capacity = cap; } size_t Size() const noexcept { return m_size; } @@ -423,7 +397,7 @@ namespace OpenVulkano size_t capacity() const noexcept { return Capacity(); } //endregion - protected: + private: VectorChunk* Grow(size_t requestSize) { VectorChunk* newChunk = static_cast( @@ -497,6 +471,15 @@ namespace OpenVulkano return InsertBack(); } + void Delete(size_t index, VectorChunk* chunk) + { + chunk->m_data[index].~T(); + chunk->m_occupiedIndices[index] = false; + chunk->m_size--; + chunk->m_gapCount++; + m_size--; + } + private: VectorChunk* m_firstChunk; VectorChunk* m_lastChunk; From c572094f77acbcc9b520b7020c916e90dc434ca0 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Thu, 10 Oct 2024 12:01:08 +0300 Subject: [PATCH 13/13] template Iterator for StableVector --- .../Data/Containers/StableVector.hpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/openVulkanoCpp/Data/Containers/StableVector.hpp b/openVulkanoCpp/Data/Containers/StableVector.hpp index 5533b12..0685f32 100644 --- a/openVulkanoCpp/Data/Containers/StableVector.hpp +++ b/openVulkanoCpp/Data/Containers/StableVector.hpp @@ -56,7 +56,6 @@ namespace OpenVulkano { if (m_occupiedIndices[i]) { - m_occupiedIndices[i] = false; m_data[i].~T(); } } @@ -93,6 +92,7 @@ namespace OpenVulkano }; public: + template class Iterator { friend class StableVector; @@ -100,13 +100,13 @@ namespace OpenVulkano public: Iterator(VectorChunk* chunk, size_t index) : m_chunk(chunk), m_index(index) {} - T& operator*() + U& operator*() { auto realIndex = m_chunk->GetRealIndex(m_index); return m_chunk->m_data[realIndex]; } - T* operator->() { return &operator*(); } + U* operator->() { return &operator*(); } Iterator& operator++() { @@ -186,6 +186,9 @@ namespace OpenVulkano }; public: + using ConstIterator = Iterator; + using RegIterator = Iterator; + StableVector(size_t size = DEFAULT_CHUNK_SIZE) : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) { @@ -194,8 +197,7 @@ namespace OpenVulkano m_capacity = size; } - StableVector(size_t size, const T& value) - : StableVector(size), m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + StableVector(size_t size, const T& value) : StableVector(size) { for (size_t i = 0; i < size; i++) { @@ -203,8 +205,7 @@ namespace OpenVulkano } } - StableVector(std::initializer_list list) - : StableVector(list.size), m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + StableVector(std::initializer_list list) : StableVector(list.size) { for (const T& value: list) { @@ -212,8 +213,7 @@ namespace OpenVulkano } } - StableVector(const StableVector& copy) - : StableVector(copy.m_size), m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + StableVector(const StableVector& copy) : StableVector(copy.m_size) { for (size_t i = 0; i < copy.Size(); i++) { @@ -221,8 +221,7 @@ namespace OpenVulkano } } - StableVector(StableVector&& move) noexcept - : m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0) + StableVector(StableVector&& move) noexcept : m_firstChunk(nullptr) { m_firstChunk = move.m_firstChunk; m_lastChunk = move.m_lastChunk; @@ -320,7 +319,7 @@ namespace OpenVulkano Delete(realIndex, handle.first); } - void Remove(const Iterator& it) + void Remove(const RegIterator& it) { if (it.m_chunk == nullptr) { @@ -347,7 +346,7 @@ namespace OpenVulkano return operator[](index); } - void Clear() + void Clear() { // Get the first chunk's cap size_t cap = m_firstChunk->m_capacity; @@ -369,6 +368,7 @@ namespace OpenVulkano m_firstChunk->m_nextIndex = 0; m_firstChunk->m_gapCount = 0; m_firstChunk->~VectorChunk(); + new (m_firstChunk) VectorChunk(cap); m_size = 0; m_capacity = cap; } @@ -377,11 +377,11 @@ namespace OpenVulkano size_t Capacity() const noexcept { return m_capacity; } bool Empty() const noexcept { return m_size == 0; } - Iterator begin() { return Iterator(m_firstChunk, 0); } - Iterator end() { return Iterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); } + RegIterator begin() { return RegIterator(m_firstChunk, 0); } + RegIterator end() { return RegIterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); } - const Iterator& cbegin() { return Iterator(m_firstChunk, 0); } - const Iterator& cend() { return Iterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); } + ConstIterator cbegin() const { return ConstIterator(m_firstChunk, 0); } + ConstIterator cend() const { return ConstIterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); } //region std aliases void push_back(const T& value) { PushBack(value); } @@ -392,7 +392,7 @@ namespace OpenVulkano T& front() { return Front(); } bool empty() const noexcept { return Empty(); } void clear() { Clear(); } - void erase(const Iterator& it) { Remove(it); } + void erase(const RegIterator& it) { Remove(it); } size_t size() const noexcept { return Size(); } size_t capacity() const noexcept { return Capacity(); } //endregion