Extra2D/Extra2D/include/extra2d/asset/asset_cache.h

264 lines
6.3 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 <extra2d/asset/asset.h>
#include <extra2d/asset/asset_handle.h>
#include <extra2d/asset/asset_types.h>
#include <extra2d/core/types.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <deque>
#include <list>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ---------------------------------------------------------------------------
// CacheEntry - 缓存条目
// ---------------------------------------------------------------------------
/**
* @brief 缓存条目结构
*
* 存储资源引用和访问信息用于LRU缓存管理。
*/
struct CacheEntry {
Ref<Asset> asset;
std::chrono::steady_clock::time_point lastAccess;
size_t accessCount = 0;
/**
* @brief 构造缓存条目
* @param a 资源引用
*/
explicit CacheEntry(Ref<Asset> a)
: asset(std::move(a)),
lastAccess(std::chrono::steady_clock::now()),
accessCount(1) {}
/**
* @brief 更新访问信息
*/
void touch() {
lastAccess = std::chrono::steady_clock::now();
++accessCount;
}
};
// ---------------------------------------------------------------------------
// AssetCache - 资源缓存
// ---------------------------------------------------------------------------
/**
* @brief 资源缓存类
*
* 实现享元模式,提供资源共享和缓存管理功能。
*
* 特性:
* - LRU缓存淘汰策略
* - 线程安全(读写锁)
* - 引用计数自动回收
* - 缓存统计和监控
* - 内存上限管理
*/
class AssetCache {
public:
/**
* @brief 构造函数
* @param limit 缓存内存上限字节0表示无限制
*/
explicit AssetCache(size_t limit = 0);
~AssetCache() = default;
AssetCache(const AssetCache&) = delete;
AssetCache& operator=(const AssetCache&) = delete;
// -------------------------------------------------------------------------
// 资源管理
// -------------------------------------------------------------------------
/**
* @brief 添加资源到缓存
* @tparam T 资源类型
* @param asset 资源引用
* @return 资源句柄
*/
template<typename T>
AssetHandle<T> add(Ref<T> asset) {
static_assert(std::is_base_of_v<Asset, T>,
"T must derive from Asset");
if (!asset) {
return AssetHandle<T>();
}
std::unique_lock<std::shared_mutex> lock(mutex_);
AssetID id = asset->id();
size_t memSize = asset->memSize();
bytes_ += memSize;
auto it = lruList_.insert(lruList_.end(), id);
entries_[id] = CacheEntryData{
ptr::makeUnique<CacheEntry>(std::static_pointer_cast<Asset>(asset)),
it
};
++stats_.count;
if (limit_ > 0 && bytes_ > limit_) {
evict();
}
return AssetHandle<T>(id, Weak<T>(asset));
}
/**
* @brief 从缓存获取资源
* @tparam T 资源类型
* @param id 资源ID
* @return 资源句柄
*/
template<typename T>
AssetHandle<T> get(const AssetID& id) {
static_assert(std::is_base_of_v<Asset, T>,
"T must derive from Asset");
std::unique_lock<std::shared_mutex> lock(mutex_);
auto it = entries_.find(id);
if (it == entries_.end()) {
++stats_.misses;
return AssetHandle<T>();
}
it->second.entry->touch();
lruList_.erase(it->second.lruIterator);
it->second.lruIterator = lruList_.insert(lruList_.end(), id);
++stats_.hits;
auto typedAsset = std::static_pointer_cast<T>(it->second.entry->asset);
return AssetHandle<T>(id, Weak<T>(typedAsset));
}
/**
* @brief 检查缓存是否包含资源
* @param id 资源ID
* @return 包含返回 true
*/
bool has(const AssetID& id) const;
/**
* @brief 从缓存移除资源
* @param id 资源ID
* @return 移除成功返回 true
*/
bool remove(const AssetID& id);
// -------------------------------------------------------------------------
// 缓存管理
// -------------------------------------------------------------------------
/**
* @brief 设置缓存内存上限
* @param limit 上限字节0表示无限制
*/
void setLimit(size_t limit);
/**
* @brief 获取缓存内存上限
* @return 上限(字节)
*/
size_t limit() const { return limit_; }
/**
* @brief 获取当前缓存内存使用量
* @return 使用量(字节)
*/
size_t bytes() const { return bytes_; }
/**
* @brief 获取缓存条目数量
* @return 条目数量
*/
size_t count() const;
/**
* @brief 获取当前缓存内存使用量(别名)
* @return 使用量(字节)
*/
size_t size() const { return bytes_; }
/**
* @brief 记录缓存命中
*/
void hit() { ++stats_.hits; }
/**
* @brief 记录缓存未命中
*/
void miss() { ++stats_.misses; }
/**
* @brief 清理无外部引用的资源
* @return 清理的资源数量
*/
size_t purge();
/**
* @brief 清空所有缓存
*/
void clear();
/**
* @brief 获取缓存统计信息
* @return 统计信息
*/
CacheStats stats() const;
/**
* @brief 重置统计信息
*/
void resetStats();
private:
/**
* @brief 缓存条目数据包含LRU迭代器
*/
struct CacheEntryData {
Ref<CacheEntry> entry;
std::list<AssetID>::iterator lruIterator;
};
/**
* @brief 淘汰资源LRU策略
*/
void evict();
/**
* @brief 检查资源是否可以被淘汰
* @param entry 缓存条目
* @return 可淘汰返回 true
*/
bool canEvict(const CacheEntry& entry) const;
mutable std::shared_mutex mutex_;
std::unordered_map<AssetID, CacheEntryData> entries_;
std::list<AssetID> lruList_;
size_t limit_ = 0;
size_t bytes_ = 0;
mutable CacheStats stats_;
};
}