Merge branch 'master' of git.madvoxel.net:OpenVulkano/OpenVulkano

This commit is contained in:
Georg Hagen
2024-10-10 14:55:28 +02:00
5 changed files with 574 additions and 304 deletions

View File

@@ -0,0 +1,100 @@
/*
* 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 <vector>
#include <map>
#include <utility>
#include <type_traits>
namespace OpenVulkano
{
template<typename K, typename V, template<typename, typename> class Pair = std::pair,
template<typename...> class Vec = std::vector, typename = std::enable_if_t<std::is_integral<K>::value>>
class BinSearchArrayMap
{
public:
void Insert(K key, const V& value)
{
// Check if the key is bigger than the last element
if (m_data.empty() || key > m_data.back().first)
{
m_data.emplace_back(key, value);
return;
}
throw std::runtime_error("Key cannot be lesser than the last used key.");
}
template<typename... Args> void Emplace(K key, Args&&... args)
{
// Check if the key is bigger than the last element
if (m_data.empty() || key > m_data.back().first)
{
m_data.emplace_back(key, std::forward<Args>(args)...);
return;
}
throw std::runtime_error("Key cannot be lesser than the last used key.");
}
void Remove(const K key)
{
std::streamsize index = FindIndexInVector(key);
m_data.erase(m_data.begin() + index);
}
size_t Size() const { return m_data.size(); }
V& operator[](const K key) noexcept { return Get(key); }
V& Get(const K key) { return FindPair(key).second; }
Pair<K, V>& FindPair(const K key)
{
std::streamsize index = FindIndexInVector(key);
if (index < 0)
{
throw std::runtime_error("Key not found");
}
return m_data[index];
}
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)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return -1;
}
bool Contains(const K key) noexcept { return FindIndexInVector(key) >= 0; }
void Clear() { m_data.clear(); }
private:
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> 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_capacity; i++)
{ {
if (m_fill[i]) if (m_occupiedIndices[i])
{ {
m_data[i].~T(); m_data[i].~T();
} }
@@ -51,104 +62,181 @@ 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++;
}
}
for (size_t i = reqIndex + gapCount; i < m_capacity; i++)
{
if (m_occupiedIndices[i])
{
return i;
}
}
return reqIndex + gapCount;
}
}; };
public: public:
template<typename U>
class Iterator class Iterator
{ {
friend class StableVector<T>;
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]; } U& operator*()
T* operator->() { return &m_ptr->m_data[m_index]; } {
auto realIndex = m_chunk->GetRealIndex(m_index);
return m_chunk->m_data[realIndex];
}
Iterator operator++() U* operator->() { return &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); ++temp;
return temp; return temp;
} }
bool operator==(const Iterator& other) const { return m_ptr == other.m_ptr && m_index == other.m_index; } Iterator& operator--()
{
--m_index;
MoveToPrevChunk();
return *this;
}
Iterator operator--(int)
{
Iterator temp = *this;
--temp;
return temp;
}
Iterator operator+(size_t n)
{
Iterator temp = *this;
temp.m_index += n;
temp.MoveToNextChunk();
return temp;
}
Iterator operator-(size_t n)
{
Iterator temp = *this;
temp.m_index -= n;
temp.MoveToPrevChunk();
return temp;
}
bool operator==(const Iterator& other) const
{
return m_chunk == other.m_chunk && m_index == other.m_index;
}
bool operator!=(const Iterator& other) const { return !(*this == other); } bool operator!=(const Iterator& other) const { return !(*this == other); }
private: private:
void MovetoNextValidChunk() void MoveToNextChunk()
{ {
while (m_ptr && (m_index > m_ptr->m_chunkSize || !m_ptr->m_fill[m_index])) while (m_chunk && m_index >= m_chunk->m_size)
{ {
if (m_index >= m_ptr->m_chunkSize) m_index -= m_chunk->m_size;
{ m_chunk = m_chunk->m_next;
m_ptr = m_ptr->m_next;
m_index = 0;
}
else ++m_index;
}
if (m_ptr && m_index >= m_ptr->m_chunkSize)
{
m_ptr = m_ptr->m_next;
m_index = 0;
MovetoNextValidChunk();
} }
} }
void MoveToPrevChunk()
{
while (m_chunk && m_index < 0)
{
m_index += m_chunk->m_size;
m_chunk = m_chunk->m_prev;
}
}
std::streamsize GetIteratorIndex() const { return m_chunk->GetRealIndex(m_index); }
private: private:
VectorChunk* m_ptr; VectorChunk* m_chunk;
size_t m_index; std::streamsize m_index;
}; };
public: public:
StableVector() : m_firstChunk(nullptr), m_lastChunk(nullptr) using ConstIterator = Iterator<const T>;
using RegIterator = Iterator<T>;
StableVector(size_t size = DEFAULT_CHUNK_SIZE)
: m_firstChunk(nullptr), m_lastChunk(nullptr), m_size(0), m_capacity(0)
{ {
VectorChunk* chunk = SpawnChunk(DEFAULT_CHUNK_SIZE); m_firstChunk = Grow(size);
m_firstChunk = chunk; m_lastChunk = m_firstChunk;
m_lastChunk = chunk; m_capacity = size;
m_currentSize = 0;
m_totalCap = DEFAULT_CHUNK_SIZE;
} }
StableVector(const StableVector<T>& copy) StableVector(size_t size, const T& value) : StableVector(size)
{ {
m_firstChunk = nullptr; for (size_t i = 0; i < size; i++)
m_lastChunk = nullptr;
m_currentSize = 0;
m_totalCap = 0;
VectorChunk* currentChunk = copy.m_firstChunk;
while (currentChunk)
{ {
for (size_t i = 0; i < currentChunk->m_chunkSize; i++) PushBack(value);
{
if (currentChunk->m_fill[i]) { PushBack(currentChunk->m_data[i]); }
}
currentChunk = currentChunk->m_next;
} }
} }
StableVector(StableVector<T>&& move) noexcept StableVector(std::initializer_list<T> list) : StableVector(list.size)
{
for (const T& value: list)
{
PushBack(value);
}
}
StableVector(const StableVector<T>& copy) : StableVector(copy.m_size)
{
for (size_t i = 0; i < copy.Size(); i++)
{
PushBack(copy.At(i));
}
}
StableVector(StableVector<T>&& move) noexcept : m_firstChunk(nullptr)
{ {
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()
{ {
// Destroy everything left
VectorChunk* currentChunk = m_firstChunk; VectorChunk* currentChunk = m_firstChunk;
while (currentChunk) while (currentChunk)
{ {
@@ -159,112 +247,26 @@ namespace OpenVulkano
} }
} }
/** void PushBack(const T& value) { new (InsertBack()) T(value); }
* Adds the value to the first empty slot in the StableVector void PushBack(T&& value) noexcept { new (InsertBack()) T(std::move(value)); }
*
* @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)
{
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(T&& value) noexcept
{
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::move(value));
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
m_currentSize++;
}
template<typename... Args> void Emplace(Args&&... args)
{
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] = T(std::forward<Args>(args)...);
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(std::forward<Args>(args)...);
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
m_currentSize++;
}
template<typename... Args> void EmplaceBack(Args&&... args) template<typename... Args> void EmplaceBack(Args&&... args)
{ {
if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize) new (InsertBack()) T(std::forward<Args>(args)...);
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++;
} }
/** void Push(const T& value) { new (Insert()) T(value); }
* Pops the last element of the StableVector void Push(T&& value) noexcept { new (Insert()) T(std::move(value)); }
* template<typename... Args> void Emplace(Args&&... args) { new (Insert()) T(std::forward<Args>(args)...); }
* @throw Please know that this pop function also reduces the chunk's lastUsedIndex
*/
void PopBack() void PopBack()
{ {
if (m_currentSize == 0) return; if (m_size == 0)
{
return; // return? or make
}
if (m_lastChunk->m_lastUsedIndex == -1) if (m_lastChunk->m_nextIndex == -1)
{ {
VectorChunk* temp = m_lastChunk; VectorChunk* temp = m_lastChunk;
m_lastChunk = m_lastChunk->m_prev; m_lastChunk = m_lastChunk->m_prev;
@@ -273,191 +275,219 @@ namespace OpenVulkano
::operator delete(temp); ::operator delete(temp);
} }
m_lastChunk->m_data[m_lastChunk->m_lastUsedIndex].~T(); m_lastChunk->m_data[m_lastChunk->m_nextIndex - 1].~T();
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = false; m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex - 1] = false;
m_lastChunk->m_lastUsedIndex--; m_lastChunk->m_size--;
m_currentSize--; m_lastChunk->m_gapCount++;
m_size--;
}
constexpr T& Back() const
{
if (m_size == 0)
{
throw std::out_of_range("Index out of range");
}
return m_lastChunk->m_data[m_lastChunk->m_nextIndex - 1];
}
constexpr T& Front() const
{
if (m_size == 0)
{
throw std::out_of_range("Index out of range");
}
return m_firstChunk->m_data[0];
} }
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!");
}
void Remove(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_data[i].~T();
currentChunk->m_fill[i] = false;
m_currentSize--;
return;
}
}
currentChunk = currentChunk->m_next;
}
}
std::vector<T> ToVector() const
{
std::vector<T> vec;
VectorChunk* currentChunk = m_firstChunk;
while (currentChunk)
{
for (size_t i = 0; i < currentChunk->m_chunkSize; i++)
{
if (currentChunk->m_fill[i])
{
vec.push_back(currentChunk->m_data[i]);
}
}
currentChunk = currentChunk->m_next;
} }
return vec; size_t realIndex = handle.first->GetRealIndex(handle.second);
} if (realIndex >= handle.first->m_size)
T& At(size_t index) const
{
if (index >= Size()) [[unlikely]]
throw std::out_of_range("Index out of range!");
return (*this)[index];
}
T& operator[](size_t index) const
{
VectorChunk* chunk = m_firstChunk;
size_t localIndex = index;
while (chunk)
{ {
if (localIndex > chunk->m_chunkSize - 1) throw std::out_of_range("Index out of range");
{
localIndex -= (chunk->m_chunkSize);
chunk = chunk->m_next;
}
else break;
} }
return chunk->m_data[localIndex]; Delete(realIndex, handle.first);
} }
size_t Size() const { return m_currentSize; } void Remove(const RegIterator& it)
size_t Capacity() const { return m_totalCap; } {
if (it.m_chunk == nullptr)
{
throw std::out_of_range("Index out of range");
}
Delete(it.GetIteratorIndex(), it.m_chunk);
}
T& operator[](size_t index) noexcept
{
auto handle = FindChunk(index);
size_t realIndex = handle.first->GetRealIndex(handle.second);
return handle.first->m_data[realIndex];
}
T& At(size_t index)
{
if (index >= m_size) [[unlikely]]
{
throw std::out_of_range("Index out of range");
}
return operator[](index);
}
void Clear() void Clear()
{ {
VectorChunk* currentChunk = m_firstChunk; // Get the first chunk's cap
size_t cap = m_firstChunk->m_capacity;
// Annihilate everything
VectorChunk* currentChunk = m_firstChunk->m_next;
while (currentChunk) while (currentChunk)
{ {
VectorChunk* temp = currentChunk; VectorChunk* temp = currentChunk;
currentChunk = currentChunk->m_next; currentChunk = currentChunk->m_next;
delete temp; temp->~VectorChunk();
::operator delete(temp);
} }
m_firstChunk = nullptr; // Reset the first chunk
m_lastChunk = nullptr; m_firstChunk->m_next = nullptr;
m_currentSize = 0;
m_totalCap = DEFAULT_CHUNK_SIZE;
m_firstChunk = SpawnChunk(DEFAULT_CHUNK_SIZE);
m_lastChunk = m_firstChunk; m_lastChunk = m_firstChunk;
m_firstChunk->m_size = 0;
m_firstChunk->m_nextIndex = 0;
m_firstChunk->m_gapCount = 0;
m_firstChunk->~VectorChunk();
new (m_firstChunk) VectorChunk(cap);
m_size = 0;
m_capacity = cap;
} }
StableVector<T>& operator=(const StableVector<T>& copy) size_t Size() const noexcept { return m_size; }
{ size_t Capacity() const noexcept { return m_capacity; }
if (this == &copy) return *this; bool Empty() const noexcept { return m_size == 0; }
Clear(); RegIterator begin() { return RegIterator(m_firstChunk, 0); }
RegIterator end() { return RegIterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); }
m_firstChunk = nullptr; ConstIterator cbegin() const { return ConstIterator(m_firstChunk, 0); }
m_lastChunk = nullptr; ConstIterator cend() const { return ConstIterator(m_lastChunk, m_lastChunk->m_nextIndex - 1); }
m_currentSize = 0;
m_totalCap = 0;
VectorChunk* currentChunk = copy.m_firstChunk; //region std aliases
void push_back(const T& value) { PushBack(value); }
for (auto it = copy.begin(); it != copy.end(); ++it) PushBack(*it); void push_back(T&& value) { PushBack(std::move(value)); }
} template<typename... Args> void emplace_back(Args&&... args) { EmplaceBack(std::forward<Args>(args)...); }
void pop_back() { PopBack(); }
StableVector<T>& operator=(StableVector<T>&& move) noexcept T& back() { return Back(); }
{ T& front() { return Front(); }
if (this == &move) return *this; bool empty() const noexcept { return Empty(); }
void clear() { Clear(); }
Clear(); void erase(const RegIterator& it) { Remove(it); }
size_t size() const noexcept { return Size(); }
m_firstChunk = move.m_firstChunk; size_t capacity() const noexcept { return Capacity(); }
m_lastChunk = move.m_lastChunk; //endregion
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: private:
VectorChunk* SpawnChunk(size_t requestedSize) VectorChunk* Grow(size_t requestSize)
{ {
VectorChunk* chunk = static_cast<VectorChunk*>( VectorChunk* newChunk = static_cast<VectorChunk*>(
::operator new(sizeof(VectorChunk) + requestedSize * sizeof(T) + requestedSize * sizeof(bool))); ::operator new(sizeof(VectorChunk) + requestSize * sizeof(T) + requestSize * sizeof(bool)));
new (chunk) VectorChunk(requestedSize); new (newChunk) VectorChunk(requestSize);
if (m_lastChunk) return newChunk;
{
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) std::pair<VectorChunk*, size_t> FindChunk(size_t index)
{ {
VectorChunk* chunk = m_firstChunk; size_t leftIndex = index;
while (chunk) VectorChunk* currentChunk = m_firstChunk;
while (currentChunk)
{ {
if (localIndex > chunk->m_chunkSize - 1) if (leftIndex < currentChunk->m_size)
{ {
localIndex -= (chunk->m_chunkSize); return { currentChunk, leftIndex };
chunk = chunk->m_next;
} }
else break;
leftIndex -= currentChunk->m_size;
currentChunk = currentChunk->m_next;
} }
return chunk; throw std::out_of_range("Index out of range");
}
T* InsertBack()
{
if (m_lastChunk->m_nextIndex == m_lastChunk->m_capacity)
{
VectorChunk* newChunk = Grow(m_lastChunk->m_capacity * GROW_FACTOR);
m_capacity += m_lastChunk->m_capacity * GROW_FACTOR;
m_lastChunk->m_next = newChunk;
newChunk->m_prev = m_lastChunk;
m_lastChunk = newChunk;
}
m_lastChunk->m_occupiedIndices[m_lastChunk->m_nextIndex] = true;
m_lastChunk->m_size++;
m_lastChunk->m_gapCount++;
m_size++;
return &m_lastChunk->m_data[m_lastChunk->m_nextIndex++];
}
T* Insert()
{
T* target = nullptr;
VectorChunk* currentChunk = m_firstChunk;
while (currentChunk)
{
if (currentChunk->m_gapCount > 0) // If there is a gap check occupied indices to find the first gap
{
for (size_t i = 0; i < currentChunk->m_capacity; i++)
{
if (!currentChunk->m_occupiedIndices[i])
{
target = &currentChunk->m_data[i];
currentChunk->m_occupiedIndices[i] = true;
currentChunk->m_size++;
currentChunk->m_gapCount--;
m_size++;
return target;
}
}
}
currentChunk = currentChunk->m_next;
}
return InsertBack();
}
void Delete(size_t index, VectorChunk* chunk)
{
chunk->m_data[index].~T();
chunk->m_occupiedIndices[index] = false;
chunk->m_size--;
chunk->m_gapCount++;
m_size--;
} }
private: 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;
static inline constexpr size_t DEFAULT_CHUNK_SIZE = 32;
static inline constexpr size_t GROW_FACTOR = 2;
}; };
} }

View File

@@ -0,0 +1,141 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <catch2/catch_all.hpp>
#include <vector>
#include <map>
#include <utility>
#include <type_traits>
#include "Data/Containers/BinSearchArrayMap.hpp"
#include "Data/Containers/StableVector.hpp"
using namespace OpenVulkano;
TEST_CASE("BinSearchArrayMap With Default")
{
SECTION("Insert")
{
BinSearchArrayMap<int, std::string> 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> map;
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.Size() == 47);
for (int i = 0; i < 50; i++)
{
if (i == 16 || i == 23 || i == 48)
{
REQUIRE(!map.Contains(i));
}
else
{
REQUIRE(map.Get(i) == std::to_string(i));
}
}
}
SECTION("Emplace")
{
BinSearchArrayMap<int, std::string> map;
for (int i = 0; i < 50; i++)
{
map.Emplace(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("FindPair")
{
BinSearchArrayMap<int, std::string> map;
for (int i = 0; i < 50; i++)
{
map.Insert(i, std::to_string(i));
}
auto pair = map.FindPair(16);
REQUIRE(pair.first == 16);
REQUIRE(pair.second == "16");
}
}
TEST_CASE("BinSearchArrayMap With StableVector")
{
SECTION("Insert")
{
BinSearchArrayMap<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");
for (int i = 0; i < 50; i++)
{
REQUIRE(map.Get(i) == std::to_string(i));
}
}
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);
map.Remove(48);
for (int i = 0; i < 50; i++)
{
if (i == 16 || i == 23 || i == 48)
{
REQUIRE(!map.Contains(i));
}
else
{
REQUIRE(map.Get(i) == std::to_string(i));
}
}
}
}

View File

@@ -95,7 +95,6 @@ TEST_CASE("MemMappedFileWrite")
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE); OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
REQUIRE(helper.Data() != nullptr); REQUIRE(helper.Data() != nullptr);
std::string testData((char*) helper.Data()); std::string testData((char*) helper.Data());
printf("size: %llu", helper.Size());
helper.Close(); helper.Close();
std::ifstream file(path, std::ios::binary); std::ifstream file(path, std::ios::binary);
@@ -112,8 +111,6 @@ TEST_CASE("MemMappedFileWrite")
} }
REQUIRE(streamData.size() == testData.size()); REQUIRE(streamData.size() == testData.size());
printf("helper size: %llu\n", helper.Size());
} }
SECTION("Actual Size") SECTION("Actual Size")

View File

@@ -136,7 +136,9 @@ TEST_CASE("ChunkVector")
REQUIRE(vec.Size() == 100); REQUIRE(vec.Size() == 100);
vec.Remove(56); vec.Remove(56);
vec.Add("z"); REQUIRE(vec[56] == "a");
vec.Push("z");
REQUIRE(vec.Size() == 100); REQUIRE(vec.Size() == 100);
REQUIRE(vec[56] == "z"); REQUIRE(vec[56] == "z");