New StableVector but Iterator is missing.

This commit is contained in:
Metehan Tuncbilek
2024-10-03 18:15:48 +03:00
parent 6661e9e9af
commit eb2ca2ff5a
4 changed files with 716 additions and 571 deletions

View File

@@ -13,8 +13,8 @@
namespace OpenVulkano namespace OpenVulkano
{ {
template<typename K, typename V, typename Pair = std::pair<K, V>, typename Vec = std::vector<Pair>, template<typename K, typename V, template<typename, typename> class Pair = std::pair,
typename = std::enable_if_t<std::is_integral<K>::value>> template<typename> class Vec = std::vector, typename = std::enable_if_t<std::is_integral<K>::value>>
class BinSearchArrayMap class BinSearchArrayMap
{ {
public: public:
@@ -44,8 +44,8 @@ namespace OpenVulkano
void Remove(const K key) void Remove(const K key)
{ {
auto& it = FindPair(key); std::streamsize index = FindIndexInVector(key);
m_data.erase(it); m_data.erase(m_data.begin() + index);
} }
size_t Size() const { return m_data.size(); } size_t Size() const { return m_data.size(); }
@@ -54,10 +54,10 @@ namespace OpenVulkano
V& Get(const K key) { return FindPair(key).second; } V& Get(const K key) { return FindPair(key).second; }
Pair& FindPair(const K key) Pair<K, V>& FindPair(const K key)
{ {
size_t low = 0; size_t low = 0;
size_t high = m_data.size() - 1; size_t high = m_data.size();
while (low <= high) while (low <= high)
{ {
@@ -65,7 +65,33 @@ namespace OpenVulkano
if (m_data[mid].first == key) 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) 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 K key) const noexcept
bool Contains(const V& value) const { return true; } {
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: private:
Vec m_data; Vec<Pair<K, V>> m_data;
}; };
} }

View File

@@ -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 #pragma once
#include "Base/Wrapper.hpp" #include "Base/Wrapper.hpp"
@@ -9,6 +15,8 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <iostream>
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4200) #pragma warning(disable : 4200)
#pragma warning(disable : 6011) #pragma warning(disable : 6011)
@@ -22,28 +30,31 @@ namespace OpenVulkano
* *
* @throw Please know that this vector creates array gaps when you remove an element. * @throw Please know that this vector creates array gaps when you remove an element.
*/ */
template<typename T, size_t DEFAULT_CHUNK_SIZE = 32, int GROWTH_FACTOR = 2> class StableVector template<typename T, size_t GROW_FACTOR = 2, size_t DEFAULT_CHUNK_SIZE = 32> class StableVector
{ {
struct VectorChunk struct VectorChunk
{ {
VectorChunk* m_prev = nullptr; VectorChunk* m_next = nullptr; // Next chunk
VectorChunk* m_next = nullptr; VectorChunk* m_prev = nullptr; // Previous chunk
size_t m_chunkSize;
int64_t m_lastUsedIndex;
bool* m_fill;
T m_data[0];
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<bool*>(m_data + size); m_occupiedIndices = reinterpret_cast<bool*>(m_data + size);
memset(m_fill, 0, size * sizeof(bool)); memset(m_occupiedIndices, 0, size * sizeof(bool));
} }
~VectorChunk() ~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(); m_data[i].~T();
} }
@@ -51,499 +62,506 @@ namespace OpenVulkano
m_prev = nullptr; m_prev = nullptr;
m_next = 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: public:
class Iterator class Iterator
{ {
public: 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_chunk->GetAlignedData(m_index); }
T* operator->() { return &m_ptr->m_data[m_index]; } T* operator->() { return &m_chunk->GetAlignedData(m_index); }
Iterator operator++() Iterator& operator++()
{ {
++m_index; ++m_index;
MovetoNextValidChunk(); MoveToNextChunk();
return *this; return *this;
} }
Iterator operator++(int) Iterator operator++(int)
{ {
Iterator temp = *this; Iterator temp = *this;
++(*this); ++m_index;
MoveToNextChunk();
return temp; return temp;
} }
Iterator operator--() Iterator& operator--()
{ {
--m_index; --m_index;
MovetoNextValidChunk(); MoveToPrevChunk();
return *this; return *this;
} }
Iterator operator--(int) Iterator operator--(int)
{ {
Iterator temp = *this; Iterator temp = *this;
--(*this); --m_index;
MoveToPrevChunk();
return temp; return temp;
} }
template<typename Init> Iterator operator=(const Init& other) Iterator operator+(size_t n)
{ {
m_ptr = other.m_ptr; Iterator temp = *this;
m_index = other.m_index; temp.m_index += n;
return *this; temp.MoveToNextChunk();
return temp;
} }
bool operator==(const Iterator& other) const { return m_ptr == other.m_ptr && m_index == other.m_index; } Iterator operator-(size_t n)
bool operator!=(const Iterator& other) const { return !(*this == other); }
private:
void MovetoNextValidChunk()
{ {
while (m_ptr && (m_index > m_ptr->m_chunkSize || !m_ptr->m_fill[m_index])) Iterator temp = *this;
{ temp.m_index -= n;
if (m_index >= m_ptr->m_chunkSize) temp.MoveToPrevChunk();
{ return temp;
m_ptr = m_ptr->m_next; }
m_index = 0;
}
else ++m_index;
}
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 -= m_chunk->m_size;
m_index = 0; m_chunk = m_chunk->m_next;
MovetoNextValidChunk();
} }
} }
void MoveToPrevChunk() {}
private: private:
VectorChunk* m_ptr; VectorChunk* m_chunk;
size_t m_index; size_t m_index;
}; };
public: 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 = Grow(DEFAULT_CHUNK_SIZE);
m_firstChunk = chunk; m_LastChunk = m_FirstChunk;
m_lastChunk = chunk; m_Capacity = DEFAULT_CHUNK_SIZE;
m_currentSize = 0; }
m_totalCap = 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<T> 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<T>& copy) StableVector(const StableVector<T>& copy)
: m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0)
{ {
m_firstChunk = nullptr; m_FirstChunk = Grow(copy.m_Capacity); // One big chunk to make Stable contiguous.
m_lastChunk = nullptr; m_LastChunk = m_FirstChunk;
m_currentSize = 0; m_Capacity = copy.m_Capacity;
m_totalCap = 0;
VectorChunk* currentChunk = copy.m_firstChunk; for (size_t i = 0; i < copy.Size(); i++)
while (currentChunk)
{ {
for (size_t i = 0; i < currentChunk->m_chunkSize; i++) PushBack(copy.At(i));
{
if (currentChunk->m_fill[i]) { PushBack(currentChunk->m_data[i]); }
}
currentChunk = currentChunk->m_next;
} }
} }
StableVector(StableVector<T>&& move) noexcept StableVector(StableVector<T>&& move) noexcept
: m_FirstChunk(nullptr), m_LastChunk(nullptr), m_Size(0), m_Capacity(0)
{ {
m_firstChunk = move.m_firstChunk; m_FirstChunk = move.m_FirstChunk;
m_lastChunk = move.m_lastChunk; m_LastChunk = move.m_LastChunk;
m_currentSize = move.m_currentSize; m_Size = move.m_Size;
m_totalCap = move.m_totalCap; m_Capacity = move.m_Capacity;
move.m_firstChunk = nullptr; move.m_FirstChunk = nullptr;
move.m_lastChunk = nullptr; move.m_LastChunk = nullptr;
move.m_currentSize = 0; move.m_Size = 0;
move.m_totalCap = 0; move.m_Capacity = 0;
} }
~StableVector() ~StableVector()
{ {
VectorChunk* currentChunk = m_firstChunk; VectorChunk* currentChunk = m_FirstChunk;
while (currentChunk) while (currentChunk)
{ {
VectorChunk* temp = currentChunk; VectorChunk* nextChunk = currentChunk->m_next;
currentChunk = currentChunk->m_next; currentChunk->~VectorChunk();
temp->~VectorChunk(); ::operator delete(currentChunk);
::operator delete(temp); 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) 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); new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(value);
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true;
m_currentSize++; 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 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)); new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(std::move(value));
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true;
m_currentSize++; m_LastChunk->m_nextIndex++;
m_LastChunk->m_size++;
m_Size++;
} }
/** /// std version of push_back(T&& value)
* std version of PushBack(const T& value) void push_back(T&& value) { PushBack(value); }
*/
void push_back(const T& value) { PushBack(value); }
/** // Checks the first available gap and inserts. If no gap it works like push_back(const T& value)
* std version of PushBack(T&& value) void Push(const T& value)
*/
void push_back(T&& value) { PushBack(std::move(value)); }
template<typename... Args> void Emplace(Args&&... args)
{ {
VectorChunk* currentChunk = m_firstChunk; VectorChunk* currentChunk = m_FirstChunk;
while (currentChunk) 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>(args)...); if (!currentChunk->m_occupiedIndices[i])
currentChunk->m_fill[i] = true; {
m_currentSize++; new (&currentChunk->m_data[i]) T(value);
currentChunk->m_occupiedIndices[i] = true;
if (i > currentChunk->m_lastUsedIndex) currentChunk->m_lastUsedIndex = i; currentChunk->m_size++;
return; 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>(args)...); // Checks the first available gap and inserts. If no gap it works like push_back(T&& value)
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true; void Push(T&& value) noexcept
m_currentSize++; {
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 (&currentChunk->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<typename... Args> void EmplaceBack(Args&&... args) template<typename... Args> void EmplaceBack(Args&&... args)
{ {
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));
new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::forward<Args>(args)...);
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
m_currentSize++;
}
/**
* std version of EmplaceBack(Args&&... args)
*/
template<typename... Args> void emplace_back(Args&&... args) { EmplaceBack(std::forward<Args>(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)
{ {
VectorChunk* temp = m_lastChunk; VectorChunk* newChunk = Grow(m_LastChunk->m_capacity * GROW_FACTOR);
m_lastChunk = m_lastChunk->m_prev; m_LastChunk->m_next = newChunk;
m_lastChunk->m_next = nullptr; newChunk->m_prev = m_LastChunk;
temp->~VectorChunk(); m_LastChunk = newChunk;
::operator delete(temp);
} }
m_lastChunk->m_data[m_lastChunk->m_lastUsedIndex].~T(); new (&m_LastChunk->m_data[m_LastChunk->m_nextIndex]) T(std::forward<Args>(args)...);
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = false; m_LastChunk->m_occupiedIndices[m_LastChunk->m_nextIndex] = true;
m_lastChunk->m_lastUsedIndex--; m_LastChunk->m_nextIndex++;
m_currentSize--; m_LastChunk->m_size++;
m_Size++;
} }
/** /// std version of emplace_back
* std version of PopBack() template<typename... Args> void emplace_back(Args&&... args) { EmplaceBack(std::forward<Args>(args)...); }
*/
// Checks the first available gap and inserts. If no gap it works like emplace_back(Args&&... args)
template<typename... Args> 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 (&currentChunk->m_data[i]) T(std::forward<Args>(args)...);
currentChunk->m_occupiedIndices[i] = true;
currentChunk->m_size++;
currentChunk->m_gapCount--;
m_Size++;
return;
}
}
}
}
EmplaceBack(std::forward<Args>(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(); } void pop_back() { PopBack(); }
constexpr T& Back() const 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 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 front
* std version of Back()
*/
constexpr T& back() const { return Back(); }
/**
* std version of Front()
*/
constexpr T& front() const { return Front(); } constexpr T& front() const { return Front(); }
void Remove(size_t index) void Remove(size_t index)
{ {
size_t localIndex = index; auto handle = FindChunk(index);
VectorChunk* chunk = GetChunk(localIndex); if (!handle.first)
if (chunk)
{ {
chunk->m_data[localIndex].~T(); throw std::out_of_range("Index out of range");
chunk->m_fill[localIndex] = false;
m_currentSize--;
} }
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) 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) size_t realIndex = currentChunk->GetRealIndex(it.m_index);
{ currentChunk->m_data[realIndex].~T();
currentChunk->m_data[i].~T(); currentChunk->m_occupiedIndices[realIndex] = false;
currentChunk->m_fill[i] = false; currentChunk->m_size--;
m_currentSize--; currentChunk->m_gapCount++;
return; m_Size--;
} return;
} }
index += currentChunk->m_size;
currentChunk = currentChunk->m_next; currentChunk = currentChunk->m_next;
} }
} }
/** T& operator[](size_t index) { return At(index); }
* std version of Remove(size_t index) T& At(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<T> ToVector() const
{ {
std::vector<T> vec; if (index >= m_Size) [[unlikely]]
VectorChunk* currentChunk = m_firstChunk; {
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<VectorChunk*>(
::operator new(sizeof(VectorChunk) + requestSize * sizeof(T) + requestSize * sizeof(bool)));
new (newChunk) VectorChunk(requestSize);
return newChunk;
}
std::pair<VectorChunk*, size_t> FindChunk(size_t index)
{
size_t leftIndex = index;
VectorChunk* currentChunk = m_FirstChunk;
while (currentChunk) while (currentChunk)
{ {
for (size_t i = 0; i < currentChunk->m_chunkSize; i++) if (leftIndex < currentChunk->m_size)
{ {
if (currentChunk->m_fill[i]) return { currentChunk, leftIndex };
{
vec.push_back(currentChunk->m_data[i]);
}
} }
leftIndex -= currentChunk->m_size;
currentChunk = currentChunk->m_next; currentChunk = currentChunk->m_next;
} }
return vec; throw std::out_of_range("Index out of range");
}
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<T>& operator=(const StableVector<T>& copy)
{
if (this == &copy) 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<T>& operator=(StableVector<T>&& 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<VectorChunk*>(
::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;
} }
private: private:
VectorChunk* m_firstChunk; VectorChunk* m_FirstChunk;
VectorChunk* m_lastChunk; VectorChunk* m_LastChunk;
size_t m_currentSize; size_t m_Size;
size_t m_totalCap; size_t m_Capacity;
}; };
} }

View File

@@ -16,24 +16,98 @@
using namespace OpenVulkano; using namespace OpenVulkano;
TEST_CASE("BinSearchArrayMap") TEST_CASE("BinSearchArrayMap With Default")
{ {
BinSearchArrayMap<int, std::string, std::pair<int, std::string>, StableVector<std::pair<int, std::string>>> map; SECTION("Insert")
{
BinSearchArrayMap<int, std::string> map;
map.Insert(1, "One"); for (int i = 0; i < 50; i++)
map.Insert(2, "Two"); {
map.Insert(6, "Three"); map.Insert(i, std::to_string(i));
map.Insert(8, "Four"); }
map.Insert(10, "Five");
REQUIRE(map.Get(1) == "One"); REQUIRE(map.Size() == 50);
REQUIRE(map.Get(2) == "Two"); REQUIRE(map.Get(16) == "16");
REQUIRE(map.Get(6) == "Three"); REQUIRE(map.Get(23) == "23");
REQUIRE(map.Get(8) == "Four"); REQUIRE(map.Get(48) == "48");
REQUIRE(map.Get(10) == "Five"); }
REQUIRE(map.Size() == 5); SECTION("Remove")
{
BinSearchArrayMap<int, std::string> map;
map.Remove(6); for (int i = 0; i < 50; i++)
REQUIRE(map.Size() == 4); {
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<int, std::string, std::pair, StableVector> 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<int, std::string, std::pair, StableVector> 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");
// }
// }
// }
//}

View File

@@ -4,187 +4,189 @@
using namespace OpenVulkano; using namespace OpenVulkano;
struct Test //struct Test
{ //{
uint32_t mValue; // uint32_t mValue;
Test(uint32_t value) : mValue(value) {} // Test(uint32_t value) : mValue(value) {}
Test() : mValue(0) {} // Test() : mValue(0) {}
}; //};
//
static int incrementCounter = 0; //static int incrementCounter = 0;
static int decrementCounter = 0; //static int decrementCounter = 0;
//
struct TestCount //struct TestCount
{ //{
TestCount() : m_value("") { ++incrementCounter; } // TestCount() : m_value("") { ++incrementCounter; }
TestCount(const std::string& val) : m_value(val) { ++incrementCounter; } // TestCount(const std::string& val) : m_value(val) { ++incrementCounter; }
TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; } // TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; }
TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; } // TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; }
//
TestCount& operator=(const TestCount& other) // TestCount& operator=(const TestCount& other)
{ // {
m_value = other.m_value; // m_value = other.m_value;
return *this; // return *this;
} // }
//
TestCount& operator=(TestCount&& other) noexcept // TestCount& operator=(TestCount&& other) noexcept
{ // {
m_value = std::move(other.m_value); // m_value = std::move(other.m_value);
return *this; // return *this;
} // }
//
~TestCount() { ++decrementCounter; } // ~TestCount() { ++decrementCounter; }
//
std::string m_value; // std::string m_value;
}; //};
//
TEST_CASE("ChunkVector") //TEST_CASE("ChunkVector")
{ //{
SECTION("PushBack") // SECTION("PushBack")
{ // {
StableVector<uint32_t> vec; // StableVector<uint32_t> vec;
//
REQUIRE(vec.Size() == 0); // REQUIRE(vec.Size() == 0);
REQUIRE(vec.Capacity() == 32); // REQUIRE(vec.Capacity() == 32);
//
for (uint32_t i = 0; i < 100; ++i) // for (uint32_t i = 0; i < 100; ++i)
{ // {
vec.PushBack(i); // vec.PushBack(i);
} // }
//
REQUIRE(vec.Size() == 100); // REQUIRE(vec.Size() == 100);
REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2 // REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2
} // }
//
SECTION("EmplaceBack") // SECTION("EmplaceBack")
{ // {
StableVector<Test> vec; // StableVector<Test> vec;
//
REQUIRE(vec.Size() == 0); // REQUIRE(vec.Size() == 0);
REQUIRE(vec.Capacity() == 32); // REQUIRE(vec.Capacity() == 32);
//
for (uint32_t i = 0; i < 100; ++i) // for (uint32_t i = 0; i < 100; ++i)
{ // {
vec.EmplaceBack(i); // vec.EmplaceBack(i);
} // }
//
REQUIRE(vec.Size() == 100); // REQUIRE(vec.Size() == 100);
//
for (uint32_t i = 0; i < 100; ++i) // for (uint32_t i = 0; i < 100; ++i)
{ // {
REQUIRE(vec[i].mValue == i); // REQUIRE(vec[i].mValue == i);
} // }
} // }
//
SECTION("PopBack") // SECTION("PopBack")
{ // {
StableVector<uint32_t> vec; // StableVector<uint32_t> vec;
//
REQUIRE(vec.Size() == 0); // REQUIRE(vec.Size() == 0);
REQUIRE(vec.Capacity() == 32); // REQUIRE(vec.Capacity() == 32);
//
for (uint32_t i = 0; i < 100; ++i) // for (uint32_t i = 0; i < 100; ++i)
{ // {
vec.PushBack(i); // vec.PushBack(i);
} // }
//
REQUIRE(vec.Size() == 100); // REQUIRE(vec.Size() == 100);
//
uint64_t tempVal = vec.Capacity(); // uint64_t tempVal = vec.Capacity();
//
for (uint32_t i = 0; i < 50; ++i) // for (uint32_t i = 0; i < 50; ++i)
{ // {
vec.PopBack(); // vec.PopBack();
} // }
//
REQUIRE(vec.Size() == 50); // REQUIRE(vec.Size() == 50);
REQUIRE(vec.Capacity() == tempVal); // REQUIRE(vec.Capacity() == tempVal);
} // }
//
SECTION("Clear") // SECTION("Clear")
{ // {
StableVector<uint32_t> vec; // StableVector<uint32_t> vec;
//
REQUIRE(vec.Size() == 0); // REQUIRE(vec.Size() == 0);
REQUIRE(vec.Capacity() == 32); // REQUIRE(vec.Capacity() == 32);
//
for (uint32_t i = 0; i < 100; ++i) // for (uint32_t i = 0; i < 100; ++i)
{ // {
vec.PushBack(i); // vec.PushBack(i);
} // }
//
REQUIRE(vec.Size() == 100); // REQUIRE(vec.Size() == 100);
//
vec.Clear(); // vec.Clear();
//
REQUIRE(vec.Size() == 0); // REQUIRE(vec.Size() == 0);
REQUIRE(vec.Capacity() == 32); // REQUIRE(vec.Capacity() == 32);
} // }
//
SECTION("Add/Fill") // SECTION("Add/Fill")
{ // {
StableVector<std::string> vec; // StableVector<std::string> vec;
//
REQUIRE(vec.Size() == 0); // REQUIRE(vec.Size() == 0);
REQUIRE(vec.Capacity() == 32); // REQUIRE(vec.Capacity() == 32);
//
for (uint32_t i = 0; i < 100; ++i) // for (uint32_t i = 0; i < 100; ++i)
{ // {
vec.PushBack("a"); // vec.PushBack("a");
} // }
//
REQUIRE(vec.Size() == 100); // REQUIRE(vec.Size() == 100);
//
vec.Remove(56); // vec.Remove(56);
vec.Add("z"); // REQUIRE(vec[56] == "a");
//
REQUIRE(vec.Size() == 100); // vec.Add("z");
REQUIRE(vec[56] == "z"); //
} // REQUIRE(vec.Size() == 100);
// REQUIRE(vec[56] == "z");
SECTION("Correct Initialization") // }
{ //
StableVector<TestCount> vec; // SECTION("Correct Initialization")
// {
REQUIRE(incrementCounter == 0); // StableVector<TestCount> vec;
REQUIRE(decrementCounter == 0); //
// REQUIRE(incrementCounter == 0);
vec.EmplaceBack("a"); // REQUIRE(decrementCounter == 0);
//
REQUIRE(incrementCounter == 1); // vec.EmplaceBack("a");
REQUIRE(decrementCounter == 0); //
// REQUIRE(incrementCounter == 1);
vec.PushBack(TestCount("b")); // REQUIRE(decrementCounter == 0);
//
REQUIRE(incrementCounter == 3); // vec.PushBack(TestCount("b"));
REQUIRE(decrementCounter == 1); //
// REQUIRE(incrementCounter == 3);
TestCount testClass = TestCount("c"); // REQUIRE(decrementCounter == 1);
vec.PushBack(std::move(testClass)); //
// TestCount testClass = TestCount("c");
REQUIRE(incrementCounter == 5); // vec.PushBack(std::move(testClass));
REQUIRE(decrementCounter == 1); //
// REQUIRE(incrementCounter == 5);
vec.Clear(); // REQUIRE(decrementCounter == 1);
//
REQUIRE(incrementCounter == 5); // vec.Clear();
REQUIRE(decrementCounter == 4); //
// REQUIRE(incrementCounter == 5);
vec.PushBack(TestCount("d")); // REQUIRE(decrementCounter == 4);
//
REQUIRE(incrementCounter == 7); // vec.PushBack(TestCount("d"));
REQUIRE(decrementCounter == 5); //
// REQUIRE(incrementCounter == 7);
TestCount testClass2 = TestCount("e"); // REQUIRE(decrementCounter == 5);
vec.PushBack(testClass2); //
// TestCount testClass2 = TestCount("e");
REQUIRE(incrementCounter == 9); // vec.PushBack(testClass2);
REQUIRE(decrementCounter == 5); //
} // REQUIRE(incrementCounter == 9);
// REQUIRE(decrementCounter == 5);
SECTION("Out of scope check") // }
{ //
REQUIRE(incrementCounter == 9); // SECTION("Out of scope check")
REQUIRE(decrementCounter == 9); // {
} // REQUIRE(incrementCounter == 9);
} // REQUIRE(decrementCounter == 9);
// }
//}