148 lines
3.8 KiB
C++
148 lines
3.8 KiB
C++
#pragma once
|
||
|
||
#include <assets/handle.h>
|
||
#include <types/ptr/intrusive_ptr.h>
|
||
#include <vector>
|
||
#include <cstdint>
|
||
|
||
namespace extra2d {
|
||
|
||
/**
|
||
* @brief 密集存储的资源仓库
|
||
*
|
||
* 使用 Dense Vec 存储,类似 ECS 的组件存储。
|
||
* 提供 O(1) 的插入、删除、访问。
|
||
*
|
||
* @tparam T 资源类型
|
||
*/
|
||
template<typename T>
|
||
class AssetStorage {
|
||
public:
|
||
struct Slot {
|
||
Ptr<T> asset;
|
||
typename Handle<T>::Generation generation = 0;
|
||
bool active = false;
|
||
};
|
||
|
||
AssetStorage() = default;
|
||
~AssetStorage() = default;
|
||
|
||
AssetStorage(const AssetStorage&) = delete;
|
||
AssetStorage& operator=(const AssetStorage&) = delete;
|
||
|
||
/**
|
||
* @brief 插入资源,返回句柄
|
||
* @param asset 资源指针
|
||
* @return 资源句柄
|
||
*/
|
||
Handle<T> insert(Ptr<T> asset) {
|
||
uint32_t index;
|
||
|
||
if (!freeIndices_.empty()) {
|
||
index = freeIndices_.back();
|
||
freeIndices_.pop_back();
|
||
slots_[index].asset = std::move(asset);
|
||
slots_[index].active = true;
|
||
} else {
|
||
index = static_cast<uint32_t>(slots_.size());
|
||
Slot slot;
|
||
slot.asset = std::move(asset);
|
||
slot.generation = nextGeneration_++;
|
||
slot.active = true;
|
||
slots_.push_back(std::move(slot));
|
||
}
|
||
|
||
++activeCount_;
|
||
return Handle<T>(index, slots_[index].generation);
|
||
}
|
||
|
||
/**
|
||
* @brief 移除资源
|
||
* @param handle 资源句柄
|
||
*/
|
||
void remove(Handle<T> handle) {
|
||
if (!isValid(handle)) return;
|
||
|
||
uint32_t index = handle.index();
|
||
slots_[index].asset.reset();
|
||
slots_[index].active = false;
|
||
slots_[index].generation = nextGeneration_++;
|
||
freeIndices_.push_back(index);
|
||
--activeCount_;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取资源(返回指针,可能为 nullptr)
|
||
* @param handle 资源句柄
|
||
* @return 资源指针
|
||
*/
|
||
T* get(Handle<T> handle) const {
|
||
if (!isValid(handle)) return nullptr;
|
||
return slots_[handle.index()].asset.get();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取资源(返回智能指针)
|
||
* @param handle 资源句柄
|
||
* @return 资源智能指针
|
||
*/
|
||
Ptr<T> getPtr(Handle<T> handle) const {
|
||
if (!isValid(handle)) return Ptr<T>();
|
||
return slots_[handle.index()].asset;
|
||
}
|
||
|
||
/**
|
||
* @brief 检查句柄是否有效
|
||
* @param handle 资源句柄
|
||
* @return 是否有效
|
||
*/
|
||
bool isValid(Handle<T> handle) const {
|
||
if (!handle.isValid()) return false;
|
||
uint32_t index = handle.index();
|
||
if (index >= slots_.size()) return false;
|
||
const Slot& slot = slots_[index];
|
||
return slot.active && slot.generation == handle.generation();
|
||
}
|
||
|
||
/**
|
||
* @brief 遍历所有资源
|
||
* @param func 回调函数,签名 void(Handle<T>, T*)
|
||
*/
|
||
template<typename Func>
|
||
void forEach(Func&& func) const {
|
||
for (size_t i = 0; i < slots_.size(); ++i) {
|
||
const Slot& slot = slots_[i];
|
||
if (slot.active && slot.asset) {
|
||
func(Handle<T>(static_cast<uint32_t>(i), slot.generation), slot.asset.get());
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 清空所有资源
|
||
*/
|
||
void clear() {
|
||
slots_.clear();
|
||
freeIndices_.clear();
|
||
activeCount_ = 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取活跃资源数量
|
||
*/
|
||
size_t count() const { return activeCount_; }
|
||
|
||
/**
|
||
* @brief 获取存储容量
|
||
*/
|
||
size_t capacity() const { return slots_.size(); }
|
||
|
||
private:
|
||
std::vector<Slot> slots_;
|
||
std::vector<uint32_t> freeIndices_;
|
||
uint32_t nextGeneration_ = 1;
|
||
size_t activeCount_ = 0;
|
||
};
|
||
|
||
} // namespace extra2d
|