Luna/libluna/include/luna/Vector.h

266 lines
4.9 KiB
C++

#pragma once
#include <luna/Alloc.h>
#include <luna/CString.h>
#include <luna/Result.h>
#include <luna/Slice.h>
#include <luna/Types.h>
template <typename T> class Vector
{
public:
typedef T* Iterator;
typedef const T* ConstIterator;
Vector()
{
}
Vector(const Vector<T>& other) = delete;
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) = delete;
Vector<T>& operator=(Vector<T>&& other)
{
if (&other == this) return *this;
if (m_data) clear();
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) { clear(); }
}
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 ? m_capacity * 2 : 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]);
}
Option<T> try_dequeue()
{
if (m_size == 0) return {};
return remove_at(0);
}
const T& operator[](usize index) const
{
check(index < m_size);
return m_data[index];
}
T& operator[](usize index)
{
check(index < m_size);
return m_data[index];
}
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;
}
T* release_data()
{
T* data = m_data;
m_data = nullptr;
m_size = m_capacity = 0;
return data;
}
Slice<T> slice()
{
return { m_data, m_size };
}
Slice<T> slice(usize index)
{
check(index < m_size);
return { m_data + index, m_size - index };
}
usize capacity() const
{
return m_capacity;
}
usize byte_capacity() const
{
return m_capacity * sizeof(T);
}
usize size() const
{
return m_size;
}
T remove_at(usize index)
{
check(index < m_size);
T item = move(m_data[index]);
memmove(m_data + index, m_data + (index + 1), (m_size - (index + 1)) * sizeof(T));
m_size--;
return move(item);
}
template <typename Callback> Option<T> remove_first_matching(Callback callback)
{
Option<usize> index = {};
for (usize i = 0; i < m_size; i++)
{
if (callback(m_data[i]))
{
index = i;
break;
}
}
if (!index.has_value()) return {};
return remove_at(index.value());
}
void clear()
{
for (usize i = 0; i < m_size; i++) { m_data[i].~T(); }
m_size = m_capacity = 0;
free_impl(m_data);
m_data = nullptr;
}
void clear_data()
{
for (usize i = 0; i < m_size; i++) { m_data[i].~T(); }
m_size = 0;
}
Result<Vector<T>> shallow_copy()
{
Vector<T> other;
TRY(other.try_reserve(m_capacity));
memcpy(other.m_data, m_data, m_size * sizeof(T));
other.m_size = m_size;
return other;
}
Result<Vector<T>> deep_copy()
{
Vector<T> other;
TRY(other.try_reserve(m_capacity));
for (usize i = 0; i < m_size; i++) { TRY(other.try_append(m_data[i])); }
return other;
}
Result<Vector<T>> deep_copy(Result<T> (*copy_function)(const T&))
{
Vector<T> other;
TRY(other.try_reserve(m_capacity));
for (usize i = 0; i < m_size; i++)
{
auto copy = TRY(copy_function(m_data[i]));
TRY(other.try_append(move(copy)));
}
return other;
}
private:
T* m_data { nullptr };
usize m_capacity { 0 };
usize m_size { 0 };
Result<void> resize(usize new_capacity)
{
if (new_capacity < m_capacity) return {};
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 {};
}
};