feat: initial DX12 foundation framework
This commit is contained in:
169
Engine/Utilities/FreeList.h
Normal file
169
Engine/Utilities/FreeList.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @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 };
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user