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); +// } +//}