Extra2D/include/assets/asset_storage.h

148 lines
3.8 KiB
C
Raw Normal View History

#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