#pragma once #include #include #include #include template class Vector { public: typedef T* Iterator; typedef const T* ConstIterator; Vector() { } Vector(const Vector& other) { reserve(other.capacity()); memcpy(m_data, other.data(), other.size()); m_size = other.size(); } 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) { 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& operator=(Vector&& 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) { for (const T& item : *this) { item.~T(); } free_impl(m_data); } } 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 + 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; } 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; } private: T* m_data { nullptr }; usize m_capacity { 0 }; usize m_size { 0 }; Result 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 {}; } };