/**
 * @file FreeList.h
 * @brief 带复用槽位的稀疏对象容器模板。
 * @details
 * free_list 维护“已使用槽位 + 空闲链”结构，支持：
 * - O(1) 近似开销的新增与删除；
 * - 删除后槽位复用，降低频繁分配释放成本；
 * - 以索引作为外部句柄，与 id 系统协同使用。
 */
#pragma once
#include "CommonHeader.h"

namespace XEngine::utl {

#if USE_STL_VECTOR
#pragma message("WARNING: using utl::free_list with std::vector result in duplicate calls to class constructor!");
#endif

template<typename T>
class free_list
{
	static_assert(sizeof(T) >= sizeof(u32));

public:
	/**
	 * @brief 构造空容器。
	 */
	free_list() = default;

	/**
	 * @brief 预留底层存储容量。
	 * @param count 预留元素数量。
	 */
	explicit free_list(u32 count)
	{
		_array.reserve(count);
	}

	/**
	 * @brief 销毁容器并校验无存活元素。
	 */
	~free_list()
	{
		assert(!_size);

#if USE_STL_VECTOR
		memset(_array.data(), 0, _array.size() * sizeof(T));
#endif
	}

	/**
	 * @brief 新增一个元素并返回槽位 ID。
	 * @tparam params 构造参数类型。
	 * @param p 构造参数。
	 * @return 新元素 ID。
	 */
	template<class ... params>
	constexpr u32 add(params&&... p)
	{
		u32 id{ u32_invalid_id };
		if (_next_free_index == u32_invalid_id)
		{
			id = (u32)_array.size();
			_array.emplace_back(std::forward<params>(p)...);
		}
		else
		{
			id = _next_free_index;
			assert(id < _array.size() && already_removed(id));
			_next_free_index = *(const u32 *const)std::addressof(_array[id]);
			new (std::addressof(_array[id])) T(std::forward<params>(p)...);
		}
		++_size;

		return id;
	}

	/**
	 * @brief 删除指定 ID 的元素并回收到空闲链。
	 * @param id 元素 ID。
	 */
	constexpr void remove(u32 id)
	{
		assert(id < _array.size() && !already_removed(id));
		T& item{ _array[id] };
		item.~T();
		DEBUG_OP(memset(std::addressof(_array[id]), 0xcc, sizeof(T)));
		*(u32 *const)std::addressof(_array[id]) = _next_free_index;
		_next_free_index = id;
		--_size;
	}

	/**
	 * @brief 获取当前有效元素数量。
	 * @return 元素数量。
	 */
	constexpr u32 size() const
	{
		return _size;
	}


	/**
	 * @brief 获取当前已分配槽位总数。
	 * @return 容量值。
	 */
	constexpr u32 capacity() const
	{
		return _array.size();
	}


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

	/**
	 * @brief 按 ID 访问元素。
	 * @param id 元素 ID。
	 * @return 元素引用。
	 */
	[[nodiscard]] constexpr T& operator[](u32 id)
	{
		assert(id < _array.size() && !already_removed(id));
		return _array[id];
	}

	/**
	 * @brief 按 ID 访问常量元素。
	 * @param id 元素 ID。
	 * @return 常量元素引用。
	 */
	[[nodiscard]] constexpr const T& operator[](u32 id) const
	{
		assert(id < _array.size() && !already_removed(id));
		return _array[id];
	}

private:
	constexpr bool already_removed(u32 id) const
	{
		if constexpr (sizeof(T) > sizeof(u32))
		{
			u32 i{ sizeof(u32) };
			const u8 *const p{ (const u8 *const)std::addressof(_array[id]) };
			while ((p[i] == 0xcc) && (i < sizeof(T))) ++i;
			return i == sizeof(T);
		}
		else
		{
			return true;
		}
	}

#if USE_STL_VECTOR
	utl::vector<T>					_array;
#else
	utl::vector<T, false>			_array;
#endif
	u32								_next_free_index{ u32_invalid_id };
	u32								_size{ 0 };
};

}
