feat: initial DX12 foundation framework
This commit is contained in:
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