apio
b8b8d20f5b
All checks were successful
continuous-integration/drone/push Build is passing
Who even thought that copying from an old pointer passed to realloc() was a good idea? Me, apparently. Additionally, the entire point of this memcpy() was to copy the data over from the old buffer (which is already freed btw) to the new buffer, which is already done by realloc. That's the entire point of realloc. The data is copied over by realloc already. And even if the old pointer is not unmapped, we scrub freed memory with useless data, so the memcpy sets the vector's buffer to that useless data as well. I don't even know how I managed to introduce so many bugs into Vector. At least it should work properly now.
186 lines
3.2 KiB
C++
186 lines
3.2 KiB
C++
#pragma once
|
|
#include <luna/Alloc.h>
|
|
#include <luna/CString.h>
|
|
#include <luna/Result.h>
|
|
#include <luna/Types.h>
|
|
|
|
template <typename T> class Vector
|
|
{
|
|
public:
|
|
typedef T* Iterator;
|
|
typedef const T* ConstIterator;
|
|
|
|
Vector()
|
|
{
|
|
}
|
|
|
|
Vector(const Vector<T>& other)
|
|
{
|
|
reserve(other.capacity());
|
|
memcpy(m_data, other.data(), other.size());
|
|
m_size = other.size();
|
|
}
|
|
|
|
Vector(Vector<T>&& other)
|
|
{
|
|
m_data = other.data();
|
|
m_capacity = other.capacity();
|
|
m_size = other.size();
|
|
|
|
other.m_capacity = other.m_size = 0;
|
|
other.m_data = nullptr;
|
|
}
|
|
|
|
Vector<T>& operator=(const Vector<T>& other)
|
|
{
|
|
if (&other == this) return *this;
|
|
|
|
if (m_data) free_impl(m_data);
|
|
|
|
m_data = nullptr;
|
|
m_capacity = m_size = 0;
|
|
|
|
reserve(other.capacity());
|
|
memcpy(m_data, other.data(), other.size());
|
|
m_size = other.size();
|
|
|
|
return *this;
|
|
}
|
|
|
|
Vector<T>& operator=(Vector<T>&& other)
|
|
{
|
|
if (&other == this) return *this;
|
|
|
|
if (m_data) free_impl(m_data);
|
|
|
|
m_data = other.data();
|
|
m_capacity = other.capacity();
|
|
m_size = other.size();
|
|
|
|
other.m_capacity = other.m_size = 0;
|
|
other.m_data = nullptr;
|
|
|
|
return *this;
|
|
}
|
|
|
|
~Vector()
|
|
{
|
|
if (m_data) free_impl(m_data);
|
|
}
|
|
|
|
Result<void> try_reserve(usize capacity)
|
|
{
|
|
return resize(capacity);
|
|
}
|
|
|
|
void reserve(usize capacity)
|
|
{
|
|
resize(capacity).release_value();
|
|
}
|
|
|
|
Result<void> try_append(T&& item)
|
|
{
|
|
if (m_capacity == m_size) TRY(resize(m_capacity + 8));
|
|
|
|
new (&m_data[m_size]) T(move(item));
|
|
|
|
m_size++;
|
|
|
|
return {};
|
|
}
|
|
|
|
Result<void> try_append(const T& item)
|
|
{
|
|
return try_append(T(item));
|
|
}
|
|
|
|
Option<T> try_pop()
|
|
{
|
|
if (m_size == 0) return {};
|
|
|
|
m_size--;
|
|
|
|
return move(m_data[m_size]);
|
|
}
|
|
|
|
const T& operator[](usize index) const
|
|
{
|
|
check(index < m_size);
|
|
return m_data[m_size];
|
|
}
|
|
|
|
T& operator[](usize index)
|
|
{
|
|
check(index < m_size);
|
|
return m_data[m_size];
|
|
}
|
|
|
|
Iterator begin()
|
|
{
|
|
return m_data;
|
|
}
|
|
|
|
ConstIterator begin() const
|
|
{
|
|
return m_data;
|
|
}
|
|
|
|
Iterator end()
|
|
{
|
|
return m_data + m_size;
|
|
}
|
|
|
|
ConstIterator end() const
|
|
{
|
|
return m_data + m_size;
|
|
}
|
|
|
|
const T* data() const
|
|
{
|
|
return m_data;
|
|
}
|
|
|
|
T* data()
|
|
{
|
|
return m_data;
|
|
}
|
|
|
|
usize capacity() const
|
|
{
|
|
return m_capacity;
|
|
}
|
|
|
|
usize byte_capacity() const
|
|
{
|
|
return m_capacity * sizeof(T);
|
|
}
|
|
|
|
usize size() const
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
m_size = m_capacity = 0;
|
|
free_impl(m_data);
|
|
m_data = nullptr;
|
|
}
|
|
|
|
private:
|
|
T* m_data { nullptr };
|
|
usize m_capacity { 0 };
|
|
usize m_size { 0 };
|
|
|
|
Result<void> resize(usize new_capacity)
|
|
{
|
|
const usize new_byte_capacity = new_capacity * sizeof(T);
|
|
|
|
void* const ptr = TRY(realloc_impl(m_data, new_byte_capacity));
|
|
|
|
m_capacity = new_capacity;
|
|
m_data = (T*)ptr;
|
|
return {};
|
|
}
|
|
};
|