Extra2D/include/assets/asset_storage.h

148 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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