/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <vector>

namespace OpenVulkano
{
	template<typename T>
	class ChunkedArrayList
	{
		size_t m_chunkSize, m_size;
		std::vector<std::vector<T>> m_chunks; //TODO optimize

		void EnsureBuffer()
		{
			if (m_chunks.empty() || m_chunks.back().capacity() - m_chunks.back().size() == 0)
			{
				m_chunks.emplace_back().reserve(m_chunkSize);
			}
		}

	public:
		ChunkedArrayList() : m_chunkSize(8192), m_size(0)
		{}

		explicit ChunkedArrayList(ChunkedArrayList<T>&& old) noexcept
			: m_chunkSize(old.m_chunkSize), m_size(old.m_size), m_chunks(std::move(old.m_chunks))
		{
			old.m_size = 0;
		}

		void Clear()
		{
			m_chunks.clear();
		}

		template<typename ...ARGS>
		T& EmplaceBack(ARGS&&... args)
		{
			EnsureBuffer();
			m_size++;
			return m_chunks.back().emplace_back(std::forward<ARGS>(args)...);
		}

		T& InsertBack(const T& value)
		{
			EnsureBuffer();
			m_size++;
			return m_chunks.back().insert(value);
		}

		T& back()
		{
			return m_chunks.back().back();
		}

		[[nodiscard]] size_t size() const noexcept
		{
			return m_size;
		}

		T& operator[](size_t n)
		{
			return m_chunks[n / m_chunkSize][n % m_chunkSize];
		}

		const T& operator[](size_t n) const
		{
			return m_chunks[n / m_chunkSize][n % m_chunkSize];
		}
	};
}
