#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) { 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) clear(); reserve(other.capacity()); for (usize i = 0; i < other.size(); i++) { new (&m_data[i]) T(other.m_data[i]); } m_size = other.size(); return *this; } 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 + 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; } 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; } 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 {}; } };