New StableVector but Iterator is missing.
This commit is contained in:
@@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 (¤tChunk->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 (¤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<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 (¤tChunk->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 == ©) 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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -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);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|||||||
Reference in New Issue
Block a user