/**
 * @file Vector.h
 * @brief 自定义动态数组容器实现。
 * @details
 * 该容器提供接近 std::vector 的常用能力，并支持可选析构策略：
 * - 动态扩容、插入、删除与无序删除；
 * - 连续内存访问与迭代器接口；
 * - 在性能敏感场景下复用底层内存分配行为。
 */
#pragma once
#include "CommonHeader.h"

namespace XEngine::utl {

/**
 * @brief 自定义连续内存动态数组。
 * @tparam T 元素类型。
 * @tparam destruct 是否在删除时调用析构。
 */
template<typename T, bool destruct = true>
class vector
{

public:
	// Default constructor. Doesn~t allocate memory.
	/**
	 * @brief 构造空容器。
	 */
	vector() = default;

	/**
	 * @brief 构造并调整到指定元素数量。
	 * @param count 目标元素数量。
	 */
	constexpr explicit vector(u64 count)
	{
		resize(count);
	}

	/**
	 * @brief 构造并填充指定数量元素。
	 * @param count 目标元素数量。
	 * @param value 填充值。
	 */
	constexpr explicit vector(u64 count, const T& value)
	{
		resize(count, value);
	}

	constexpr vector(const vector& o)
	{
		*this = o;
	}

	constexpr vector(vector&& o)
		:_capacity{o._capacity},
		_size{o._size},
		_data{o._data}
	{
		o.reset();
	}


	constexpr vector& operator=(const vector& o)
	{
		assert(this != std::addressof(o));
		if (this != std::addressof(o))
		{
			clear();
			reserve(o._size);
			for (auto& item : o)
			{
				emplace_back(item);
			}
			assert(_size == o._size);
		}

		return *this;
	}

	constexpr vector& operator=(vector&& o)
	{
		assert(this != std::addressof(o));
		if (this != std::addressof(o))
		{
			destroy();
			move(o);
		}

		return *this;
	}

	~vector() { destroy(); }

	/**
	 * @brief 追加拷贝元素。
	 * @param value 元素值。
	 */
	constexpr void push_back(const T& value)
	{
		emplace_back(value);
	}

	/**
	 * @brief 追加右值元素。
	 * @param value 元素值。
	 */
	constexpr void push_back(const T&& value)
	{
		emplace_back(std::move(value));
	}

	/**
	 * @brief 原位构造并追加元素。
	 * @tparam params 构造参数类型。
	 * @param p 构造参数。
	 * @return 新元素引用。
	 */
	template<typename... params>
	constexpr decltype(auto) emplace_back(params&&... p)
	{
		if (_size == _capacity)
		{
			reserve(((_capacity + 1) * 3) >> 1); // reserve 50% more
		}
		assert(_size < _capacity);

		T *const item{ new (std::addressof(_data[_size])) T(std::forward<params>(p)...) };
		++_size;
		return *item;
	}

	/**
	 * @brief 调整元素数量，新增元素默认构造。
	 * @param new_size 新大小。
	 */
	constexpr void resize(u64 new_size)
	{
		static_assert(std::is_default_constructible<T>::value,
			"Type must be default-constructible.");

		if (new_size > _size)
		{
			reserve(new_size);
			while (_size < new_size)
			{
				emplace_back();
			}
		}
		else if (new_size < _size)
		{
			if constexpr (destruct)
			{
				destruct_range(new_size, _size);
			}

			_size = new_size;
		}


		assert(new_size == _size);
	}


	/**
	 * @brief 调整元素数量，新增元素使用给定值填充。
	 * @param new_size 新大小。
	 * @param value 填充值。
	 */
	constexpr void resize(u64 new_size, const T& value)
	{
		static_assert(std::is_copy_constructible<T>::value,
			"Type must be copy-constructible.");

		if (new_size > _size)
		{
			reserve(new_size);
			while (_size < new_size)
			{
				emplace_back(value);
			}
		}
		else if (new_size < _size)
		{
			if constexpr (destruct)
			{
				destruct_range(new_size, _size);
			}

			_size = new_size;
		}


		assert(new_size == _size);
	}


	/**
	 * @brief 预留最小容量。
	 * @param new_capacity 目标容量。
	 */
	constexpr void reserve(u64 new_capacity)
	{
		if (new_capacity > _capacity)
		{
			// NOTE: realoc() will automatically copy the data in the buffer
			//		 if a new region of memory iss allocated.
			void* new_buffer{ realloc(_data, new_capacity * sizeof(T)) };
			assert(new_buffer);
			if (new_buffer)
			{
				_data = static_cast<T*>(new_buffer);
				_capacity = new_capacity;
			}
		}
	}

	/**
	 * @brief 删除指定下标元素并保持顺序。
	 * @param index 删除下标。
	 * @return 指向删除位置的指针。
	 */
	constexpr T *const erase(u64 index)
	{
		assert(_data && index < _size);
		return erase(std::addressof(_data[index]));
	}

	/**
	 * @brief 删除指定位置元素并保持顺序。
	 * @param item 待删除元素指针。
	 * @return 指向删除位置的指针。
	 */
	constexpr T *const erase(T *const item)
	{
		assert(_data && item >= std::addressof(_data[0]) &&
			item < std::addressof(_data[_size]));

		if constexpr (destruct) item->~T();
		--_size;
		if (item < std::addressof(_data[_size]))
		{
			memcpy(item, item + 1, (std::addressof(_data[_size]) - item) * sizeof(T));
		}

		return item;
	}

	/**
	 * @brief 无序删除指定下标元素。
	 * @param index 删除下标。
	 * @return 指向删除位置的指针。
	 */
	constexpr T *const erase_unordered(u64 index)
	{
		assert(_data && index < _size);
		return erase_unordered(std::addressof(_data[index]));
	}

	/**
	 * @brief 无序删除指定位置元素。
	 * @param item 待删除元素指针。
	 * @return 指向删除位置的指针。
	 */
	constexpr T *const erase_unordered(T *const item)
	{
		assert(_data && item >= std::addressof(_data[0]) &&
			item < std::addressof(_data[_size]));

		if constexpr (destruct) item->~T();
		--_size;

		if (item < std::addressof(_data[_size]))
		{
			memcpy(item, std::addressof(_data[_size]), sizeof(T));
		}

		return item;
	}

	/**
	 * @brief 清空容器中的有效元素。
	 */
	constexpr void clear()
	{
		if constexpr (destruct)
		{
			destruct_range(0, _size);
		}
		_size = 0;
	}


	/**
	 * @brief 与另一个容器交换内容。
	 * @param o 目标容器。
	 */
	constexpr void swap(vector& o)
	{
		if (this != std::addressof(o))
		{
			auto temp(std::move(o));
			o.move(*this);
			move(temp);
		}
	}


	/**
	 * @brief 返回底层数据指针。
	 * @return 数据首地址。
	 */
	[[nodiscard]] constexpr T* data()
	{
		return _data;
	}


	/**
	 * @brief 返回只读底层数据指针。
	 * @return 数据首地址。
	 */
	[[nodiscard]] constexpr T *const data() const
	{
		return _data;
	}

	/**
	 * @brief 判断容器是否为空。
	 * @return 空返回 true。
	 */
	[[nodiscard]] constexpr bool empty() const
	{
		return _size == 0;
	}

	/**
	 * @brief 获取元素个数。
	 * @return 元素数量。
	 */
	[[nodiscard]] constexpr u64 size() const
	{
		return _size;
	}


	/**
	 * @brief 获取当前容量。
	 * @return 容量值。
	 */
	[[nodiscard]] constexpr u64 capacity() const
	{
		return _capacity;
	}


	[[nodiscard]] constexpr T& operator [](u64 index)
	{
		assert(_data && index < _size);
		return _data[index];
	}

	[[nodiscard]] constexpr const T& operator [](u64 index) const
	{
		assert(_data && index < _size);
		return _data[index];
	}

	[[nodiscard]] constexpr T& front()
	{
		assert(_data && _size);
		return _data[0];
	}


	[[nodiscard]] constexpr const T& front() const
	{
		assert(_data && _size);
		return _data[0];
	}

	[[nodiscard]] constexpr T& back()
	{
		assert(_data && _size);
		return _data[_size -1];
	}

	[[nodiscard]] constexpr const T& back() const
	{
		assert(_data && _size);
		return _data[_size - 1];
	}


	[[nodiscard]] constexpr T* begin()
	{
		return std::addressof(_data[0]);
	}


	[[nodiscard]] constexpr const T* begin() const
	{
		return std::addressof(_data[0]);
	}

	[[nodiscard]] constexpr T* end()
	{
		assert(!(_data == nullptr && _size > 0));
		return std::addressof(_data[_size]);
	}

	[[nodiscard]] constexpr const T* end() const
	{
		assert(!(_data == nullptr && _size > 0));
		return std::addressof(_data[_size]);
	}
private:

	constexpr void move(vector& o)
	{
		_capacity = o._capacity;
		_size = o._size;
		_data = o._data;
		o.reset();
	}

	constexpr void reset()
	{
		_capacity = 0;
		_size = 0;
		_data = nullptr;
	}

	constexpr void destruct_range(u64 first, u64 last)
	{
		assert(destruct);
		assert(first <= _size && last <= _size && first <= last);
		if (_data)
		{
			for (; first != last; ++first)
			{
				_data[first].~T();
			}
		}
	}

	constexpr void destroy()
	{
		assert([&] {return _capacity ? _data != nullptr : _data == nullptr; }());
		clear();
		_capacity = 0;
		if (_data) free(_data);
		_data = nullptr;
	}

	u64			_capacity{ 0 };
	u64			_size{ 0 };
	T*			_data{ nullptr };
};


}

