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 };
|
||||
};
|
||||
|
||||
}
|
||||
154
Engine/Utilities/IOStream.h
Normal file
154
Engine/Utilities/IOStream.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @file IOStream.h
|
||||
* @brief 面向内存缓冲区的二进制流读写工具。
|
||||
* @details
|
||||
* 定义 reader/writer 两个轻量类,用于在连续内存上顺序序列化:
|
||||
* - 支持算术类型按字节写入与读取;
|
||||
* - 支持原始块拷贝与位置跳过;
|
||||
* - 通过边界断言降低越界读写风险。
|
||||
*/
|
||||
#pragma once
|
||||
#include "CommonHeader.h"
|
||||
|
||||
namespace XEngine::utl {
|
||||
|
||||
/**
|
||||
* @brief 只读内存二进制流。
|
||||
*/
|
||||
class blob_stream_reader
|
||||
{
|
||||
public:
|
||||
DISABLE_COPY_AND_MOVE(blob_stream_reader);
|
||||
/**
|
||||
* @brief 绑定外部只读缓冲区。
|
||||
* @param buffer 缓冲区首地址。
|
||||
*/
|
||||
explicit blob_stream_reader(const u8* buffer)
|
||||
:_buffer{buffer}, _position{buffer}
|
||||
{
|
||||
assert(buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按类型读取一个值并推进游标。
|
||||
* @tparam T 算术类型。
|
||||
* @return 读取到的值。
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] T reader()
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "Template argument should be a primitive type.");
|
||||
T value{ *((T*)_position) };
|
||||
_position += sizeof(T);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取原始字节块并推进游标。
|
||||
* @param buffer 输出缓冲区。
|
||||
* @param length 读取字节数。
|
||||
*/
|
||||
void read(u8* buffer, size_t length)
|
||||
{
|
||||
memcpy(buffer, _position, length);
|
||||
_position += length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 跳过指定字节数。
|
||||
* @param offset 偏移字节数。
|
||||
*/
|
||||
void skip(size_t offset)
|
||||
{
|
||||
_position += offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const u8 *const buffer_start() const { return _buffer; }
|
||||
[[nodiscard]] constexpr const u8 *const position() const { return _position; }
|
||||
[[nodiscard]] constexpr size_t offset() const { return _position - _buffer; }
|
||||
|
||||
private:
|
||||
const u8 *const _buffer;
|
||||
const u8* _position;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 可写内存二进制流。
|
||||
*/
|
||||
class blob_stream_writer
|
||||
{
|
||||
public:
|
||||
DISABLE_COPY_AND_MOVE(blob_stream_writer);
|
||||
/**
|
||||
* @brief 绑定外部可写缓冲区。
|
||||
* @param buffer 缓冲区首地址。
|
||||
* @param buffer_size 缓冲区大小。
|
||||
*/
|
||||
explicit blob_stream_writer(u8* buffer, size_t buffer_size)
|
||||
:_buffer{ buffer }, _position{ buffer }, _buffer_size(buffer_size)
|
||||
{
|
||||
assert(buffer && buffer_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 写入一个算术类型值并推进游标。
|
||||
* @tparam T 算术类型。
|
||||
* @param value 待写入值。
|
||||
*/
|
||||
template<typename T>
|
||||
void write(T value)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "Template argument should be a primitive type.");
|
||||
assert(&_position[sizeof(T)] <= &_buffer[_buffer_size]);
|
||||
*((T*)_position) = value;
|
||||
_position += sizeof(T);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写入字符缓冲区。
|
||||
* @param buffer 输入缓冲区。
|
||||
* @param length 写入字节数。
|
||||
*/
|
||||
void write(const char* buffer, size_t length)
|
||||
{
|
||||
assert(&_position[length] <= &_buffer[_buffer_size]);
|
||||
memcpy(_position, buffer, length);
|
||||
_position += length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写入字节缓冲区。
|
||||
* @param buffer 输入缓冲区。
|
||||
* @param length 写入字节数。
|
||||
*/
|
||||
void write(const u8* buffer, size_t length)
|
||||
{
|
||||
assert(&_position[length] <= &_buffer[_buffer_size]);
|
||||
memcpy(_position, buffer, length);
|
||||
_position += length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 跳过指定字节数。
|
||||
* @param offset 偏移字节数。
|
||||
*/
|
||||
void skip(size_t offset)
|
||||
{
|
||||
assert(&_position[offset] <= &_buffer[_buffer_size]);
|
||||
_position += offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const u8 *const buffer_start() const { return _buffer; }
|
||||
[[nodiscard]] constexpr const u8 *const buffer_end() const { return &_buffer[_buffer_size]; }
|
||||
[[nodiscard]] constexpr const u8 *const position() const { return _position; }
|
||||
[[nodiscard]] constexpr size_t offset() const { return _position - _buffer; }
|
||||
|
||||
private:
|
||||
u8 *const _buffer;
|
||||
u8* _position;
|
||||
size_t _buffer_size;
|
||||
};
|
||||
}
|
||||
185
Engine/Utilities/Math.h
Normal file
185
Engine/Utilities/Math.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @file Math.h
|
||||
* @brief 数学工具函数与二进制对齐辅助函数。
|
||||
* @details
|
||||
* 提供模板化的数值打包/解包与内存对齐能力,包括:
|
||||
* - clamp 与归一化浮点量化打包;
|
||||
* - 固定/动态对齐粒度下的向上与向下对齐;
|
||||
* - 基于 SIMD 指令的 CRC32 快速计算辅助。
|
||||
*/
|
||||
#pragma once
|
||||
#include "CommonHeader.h"
|
||||
#include "MathTypes.h"
|
||||
|
||||
namespace XEngine::math {
|
||||
|
||||
/**
|
||||
* @brief 将值限制在给定区间内。
|
||||
* @tparam T 标量类型。
|
||||
* @param value 输入值。
|
||||
* @param min 下界。
|
||||
* @param max 上界。
|
||||
* @return 限制后的值。
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T
|
||||
clamp(T value, T min, T max)
|
||||
{
|
||||
return (value < min) ? min : (value > max) ? max : value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将 [0,1] 浮点值量化到指定位宽的无符号整数。
|
||||
* @tparam bits 量化位宽。
|
||||
* @param i 归一化输入值。
|
||||
* @return 量化结果。
|
||||
*/
|
||||
template<u32 bits>
|
||||
[[nodiscard]] constexpr u32
|
||||
pack_unit_float(f32 i)
|
||||
{
|
||||
static_assert(bits <= sizeof(u32) * 8);
|
||||
assert(i >= 0.f && i <= 1.f);
|
||||
constexpr f32 intervals{ (f32)(((u32)1 << bits) - 1) };
|
||||
return (u32)(intervals * i + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将 [min,max] 浮点值量化到指定位宽。
|
||||
* @tparam bits 量化位宽。
|
||||
* @param i 输入值。
|
||||
* @param min 下界。
|
||||
* @param max 上界。
|
||||
* @return 量化结果。
|
||||
*/
|
||||
template<u32 bits>
|
||||
[[nodiscard]] constexpr u32
|
||||
pack_float(f32 i, f32 min, f32 max)
|
||||
{
|
||||
assert(min < max);
|
||||
assert(i <= max && i >= min);
|
||||
const f32 distance{ (i - min) / (max - min) };
|
||||
return pack_unit_float<bits>(distance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将量化整数还原为 [0,1] 浮点值。
|
||||
* @tparam bits 量化位宽。
|
||||
* @param i 量化输入值。
|
||||
* @return 反量化结果。
|
||||
*/
|
||||
template<u32 bits>
|
||||
[[nodiscard]] constexpr f32
|
||||
unpack_unit_float(u32 i)
|
||||
{
|
||||
static_assert(bits <= sizeof(u32) * 8);
|
||||
assert(i < ((u32)i << bits));
|
||||
constexpr f32 intervals{ (f32)(((u32)1 << bits) - 1) };
|
||||
return (f32)i / intervals;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将量化值还原到 [min,max] 区间。
|
||||
* @tparam bits 量化位宽。
|
||||
* @param i 量化输入值。
|
||||
* @param min 下界。
|
||||
* @param max 上界。
|
||||
* @return 反量化结果。
|
||||
*/
|
||||
template<u32 bits>
|
||||
[[nodiscard]] constexpr f32
|
||||
unpack_float(f32 i, f32 min, f32 max)
|
||||
{
|
||||
assert(min < max);
|
||||
return unpack_unit_float<bits>(i) * (max - min) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按固定对齐值向上对齐。
|
||||
* @tparam alignment 对齐粒度(2 的幂)。
|
||||
* @param size 原始大小。
|
||||
* @return 向上对齐后的大小。
|
||||
*/
|
||||
template<u64 alignment>
|
||||
[[nodiscard]] constexpr u64
|
||||
align_size_up(u64 size)
|
||||
{
|
||||
static_assert(alignment, "Alignment must be non-zero.");
|
||||
constexpr u64 mask{ alignment - 1 };
|
||||
static_assert(!(alignment & mask), "Alignment should be a power of 2.");
|
||||
return ((size + mask) & ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按固定对齐值向下对齐。
|
||||
* @tparam alignment 对齐粒度(2 的幂)。
|
||||
* @param size 原始大小。
|
||||
* @return 向下对齐后的大小。
|
||||
*/
|
||||
template<u64 alignment>
|
||||
[[nodiscard]] constexpr u64
|
||||
align_size_down(u64 size)
|
||||
{
|
||||
static_assert(alignment, "Alignment must be non-zero.");
|
||||
constexpr u64 mask{ alignment - 1 };
|
||||
static_assert(!(alignment & mask), "Alignment should be a power of 2.");
|
||||
return (size & ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按运行时对齐值向上对齐。
|
||||
* @param size 原始大小。
|
||||
* @param alignment 对齐粒度(2 的幂)。
|
||||
* @return 向上对齐后的大小。
|
||||
*/
|
||||
[[nodiscard]] constexpr u64
|
||||
align_size_up(u64 size, u64 alignment)
|
||||
{
|
||||
assert(alignment && "Alignment must be non-zero.");
|
||||
const u64 mask{ alignment - 1 };
|
||||
assert(!(alignment & mask) && "Alignment should be a power of 2.");
|
||||
return ((size + mask) & ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按运行时对齐值向下对齐。
|
||||
* @param size 原始大小。
|
||||
* @param alignment 对齐粒度(2 的幂)。
|
||||
* @return 向下对齐后的大小。
|
||||
*/
|
||||
[[nodiscard]] constexpr u64
|
||||
align_size_down(u64 size, u64 alignment)
|
||||
{
|
||||
assert(alignment && "Alignment must be non-zero.");
|
||||
const u64 mask{ alignment - 1 };
|
||||
assert(!(alignment & mask) && "Alignment should be a power of 2.");
|
||||
return (size & ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算数据块的 64 位 CRC32 累积值。
|
||||
* @param data 输入字节流。
|
||||
* @param size 输入长度。
|
||||
* @return CRC32 累积结果。
|
||||
*/
|
||||
[[nodiscard]] constexpr u64
|
||||
calcect_crc32_u64(const u8 *const data, u64 size)
|
||||
{
|
||||
assert(size >= sizeof(u64));
|
||||
u64 crc{ 0 };
|
||||
const u8* at{ data };
|
||||
const u8 *const end{ data + align_size_down<sizeof(u64)>(size) };
|
||||
while (at < end)
|
||||
{
|
||||
crc = _mm_crc32_u64(crc, *((const u64*)at));
|
||||
at += sizeof(u64);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
}
|
||||
80
Engine/Utilities/MathTypes.h
Normal file
80
Engine/Utilities/MathTypes.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file MathTypes.h
|
||||
* @brief 数学常量与 DirectX 数学类型别名集合。
|
||||
* @details
|
||||
* 统一定义引擎常用数学基础元素:
|
||||
* - 常量:pi、two_pi、epsilon;
|
||||
* - 向量/矩阵别名:v2/v3/v4、m3x3/m4x4 等;
|
||||
* - 与 Win64 下 DirectXMath 类型的映射与对齐变体。
|
||||
*/
|
||||
#pragma once
|
||||
#include "CommonHeader.h"
|
||||
|
||||
namespace XEngine::math {
|
||||
|
||||
//constexpr long double pi = 3.141592653589793238462643383279L;
|
||||
/**
|
||||
* @brief 圆周率常量。
|
||||
*/
|
||||
constexpr float pi = 3.1415927f;
|
||||
/**
|
||||
* @brief 两倍圆周率常量。
|
||||
*/
|
||||
constexpr float two_pi = 6.2831853f;
|
||||
|
||||
/**
|
||||
* @brief 浮点比较容差常量。
|
||||
*/
|
||||
constexpr float epsilon = 1e-5f;
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
/**
|
||||
* @brief DirectXMath 向量类型别名。
|
||||
* @details
|
||||
* - 无 A 后缀类型使用常规布局;
|
||||
* - A 后缀类型要求 16 字节对齐,适合 SIMD 对齐访问场景。
|
||||
*/
|
||||
using v2 = DirectX::XMFLOAT2;
|
||||
using v2a = DirectX::XMFLOAT2A;
|
||||
using v3 = DirectX::XMFLOAT3;
|
||||
using v3a = DirectX::XMFLOAT3A;
|
||||
using v4 = DirectX::XMFLOAT4;
|
||||
using v4a = DirectX::XMFLOAT4A;
|
||||
|
||||
/**
|
||||
* @brief DirectXMath 整型向量别名。
|
||||
*/
|
||||
using u32v2 = DirectX::XMUINT2;
|
||||
using u32v3 = DirectX::XMUINT3;
|
||||
using u32v4 = DirectX::XMUINT4;
|
||||
using s32v2 = DirectX::XMINT2;
|
||||
using s32v3 = DirectX::XMINT3;
|
||||
using s32v4 = DirectX::XMINT4;
|
||||
|
||||
/**
|
||||
* @brief 标量浮点向量别名。
|
||||
*/
|
||||
using f32v2 = DirectX::XMFLOAT2;
|
||||
using f32v3 = DirectX::XMFLOAT3;
|
||||
using f32v4 = DirectX::XMFLOAT4;
|
||||
|
||||
/**
|
||||
* @brief DirectXMath 矩阵与寄存器向量别名。
|
||||
*/
|
||||
using Vec4 = DirectX::XMVECTOR;
|
||||
using Mat4 = DirectX::XMMATRIX;
|
||||
using Mat3 = DirectX::XMFLOAT3X3;
|
||||
using Mat4f = DirectX::XMFLOAT4X4;
|
||||
using m3x3 = DirectX::XMFLOAT3X3;
|
||||
using m4x4 = DirectX::XMFLOAT4X4;
|
||||
using m4x4a = DirectX::XMFLOAT4X4A;
|
||||
using vector4 = DirectX::XMVECTOR;
|
||||
using MAT4 = DirectX::XMMATRIX;
|
||||
using vector = DirectX::XMVECTOR;
|
||||
using Quat = DirectX::XMVECTOR;
|
||||
|
||||
#endif // (_WIN64)
|
||||
|
||||
|
||||
}
|
||||
86
Engine/Utilities/Utilities.h
Normal file
86
Engine/Utilities/Utilities.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file Utilities.h
|
||||
* @brief 公共容器与工具模块聚合入口。
|
||||
* @details
|
||||
* 通过编译开关统一切换 STL 与自定义容器实现,并集中导出:
|
||||
* - vector/deque 等基础容器别名;
|
||||
* - erase_unordered 辅助函数;
|
||||
* - FreeList 等常用数据结构头文件。
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
/**
|
||||
* @brief 是否使用 STL vector 作为基础容器。
|
||||
*/
|
||||
#define USE_STL_VECTOR 0
|
||||
/**
|
||||
* @brief 是否启用 STL deque 别名。
|
||||
*/
|
||||
#define USE_STL_DRQUE 1
|
||||
|
||||
#if USE_STL_VECTOR
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
namespace XEngine::utl {
|
||||
template<typename T>
|
||||
using vector = std::vector<T>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 通过交换尾元素方式无序删除。
|
||||
* @tparam T 容器类型。
|
||||
* @param v 目标容器。
|
||||
* @param index 删除下标。
|
||||
*/
|
||||
template<typename T>
|
||||
void erase_unordered(T& v, size_t index)
|
||||
{
|
||||
if (v.size() > 1)
|
||||
{
|
||||
std::iter_swap(v.begin() + index, v.end() - 1);
|
||||
v.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
v.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
#include "Vector.h"
|
||||
|
||||
namespace XEngine::utl {
|
||||
/**
|
||||
* @brief 调用自定义容器的无序删除接口。
|
||||
* @tparam T 容器类型。
|
||||
* @param v 目标容器。
|
||||
* @param index 删除下标。
|
||||
*/
|
||||
template<typename T>
|
||||
void erase_unordered(T& v, size_t index)
|
||||
{
|
||||
v.erase_unordered(index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_STL_DRQUE
|
||||
#include <deque>
|
||||
namespace XEngine::utl {
|
||||
template<typename T>
|
||||
using deque = std::deque<T>;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
namespace XEngine::utl {
|
||||
}
|
||||
|
||||
#include "FreeList.h"
|
||||
463
Engine/Utilities/Vector.h
Normal file
463
Engine/Utilities/Vector.h
Normal file
@@ -0,0 +1,463 @@
|
||||
/**
|
||||
* @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 };
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user