#pragma once #include #include #include #include #include #include template class Vector { public: typedef T* Iterator; typedef const T* ConstIterator; Vector() { } Vector(const Vector& other) = delete; Vector(Vector&& 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& operator=(const Vector& other) = delete; Vector& operator=(Vector&& 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 try_reserve(usize capacity) { return resize(capacity); } void reserve(usize capacity) { resize(capacity).release_value(); } Result 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 try_append(const T& item) { return try_append(T(item)); } Option try_pop() { if (m_size == 0) return {}; m_size--; return move(m_data[m_size]); } Option 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 slice() { return { m_data, m_size }; } Slice 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 Option remove_first_matching(Callback callback) { Option 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> shallow_copy() { Vector 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> deep_copy() { Vector 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> deep_copy(Result (*copy_function)(const T&)) { Vector 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; } template void mutate(Callback callback) { usize size = callback(m_data, m_capacity); m_size = min(m_capacity, size); } private: T* m_data { nullptr }; usize m_capacity { 0 }; usize m_size { 0 }; Result 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 {}; } };