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
|