Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <Core/FxBitset.hpp>
- #include <Core/FxHash.hpp>
- #include <Core/FxSizedArray.hpp>
- #include <map>
- /**
- * @brief Cache section that can hold any number of items.
- */
- template <typename TItemType>
- struct FxItemCacheSection_MultiItem
- {
- FxBitset ItemsInUse;
- FxSizedArray<TItemType> Items;
- public:
- void Create(uint32 max_items)
- {
- Items.Create(max_items);
- ItemsInUse.InitZero(max_items);
- }
- TItemType* RequestNewItem()
- {
- int index = ItemsInUse.FindNextFreeBit();
- if (index == FxBitset::scNoFreeBits) {
- return nullptr;
- }
- ItemsInUse.Set(index);
- return &Items[index];
- }
- void ReleaseItem(TItemType* item)
- {
- auto item_index = Items.GetItemIndex(item);
- // If the item was found, clear the bit
- if (item_index != FxSizedArray<TItemType>::scItemNotFound) {
- ItemsInUse.Unset(item_index);
- }
- }
- };
- /**
- * @brief Cache section that holds a single item.
- */
- template <typename TItemType>
- struct FxItemCacheSection_SingleItem
- {
- using ItemType = TItemType;
- TItemType* pItem = nullptr;
- bool bInUse : 1 = 0;
- public:
- void Create(uint32 max_items) { pItem = FxMemPool::Alloc<TItemType>(sizeof(TItemType)); }
- TItemType* RequestNewItem()
- {
- if (bInUse) {
- return nullptr;
- }
- bInUse = true;
- return pItem;
- }
- void ReleaseItem(TItemType* item)
- {
- if (pItem != item) {
- return;
- }
- bInUse = false;
- }
- };
- template <typename T, typename TItemType>
- concept C_IsItemCacheSection =
- C_IsAnyBaseOf<T, FxItemCacheSection_MultiItem<TItemType>, FxItemCacheSection_SingleItem<TItemType>>;
- template <typename TKeyType, typename TItemType, typename TCacheSectionType>
- requires C_IsItemCacheSection<TCacheSectionType, TItemType>
- class FxItemCache
- {
- public:
- using KeyType = TKeyType;
- public:
- FxItemCache() = default;
- void Create(uint32 max_items_per_section) { mItemsPerSection = max_items_per_section; }
- bool IsItemInCache(TKeyType key)
- {
- auto section_it = mCache.find(key);
- return (section_it == mCache.end());
- }
- TItemType* RequestGenericItem(TKeyType key)
- {
- auto section_it = mCache.find(key);
- if (section_it == mCache.end()) {
- CreateCacheSection(key, mItemsPerSection);
- auto section_it = mCache.find(key);
- FxAssert(section_it != mCache.end());
- }
- TCacheSectionType& section = section_it->second;
- return section.RequestNewItem();
- }
- void ReleaseGenericItem(TKeyType key, TItemType* item)
- {
- auto section_it = mCache.find(key);
- if (section_it == mCache.end()) {
- FxLogError("Could not find cache section to free from!");
- return;
- }
- TCacheSectionType& section = section_it->second;
- auto item_index = section.Items.GetItemIndex(item);
- // If the item was found, clear the bit
- if (item_index != FxSizedArray<TItemType>::scItemNotFound) {
- section.ItemsInUse.Unset(item_index);
- }
- }
- void Destroy();
- virtual ~FxItemCache() { Destroy(); }
- protected:
- TCacheSectionType& CreateCacheSection(TKeyType key, uint32 number_of_items)
- {
- TCacheSectionType cache_section {};
- cache_section.Items.InitCapacity(number_of_items);
- cache_section.ItemsInUse.InitZero(number_of_items);
- auto iter = mCache.insert({ key, std::move(cache_section) });
- return iter.first->second;
- }
- public:
- std::unordered_map<TKeyType, TCacheSectionType> mCache;
- protected:
- uint32 mItemsPerSection = 0;
- };
- /**
- * @brief A temporary handle that is available only for the current scope.
- */
- template <typename TKeyType, typename TItemType, typename TCacheType>
- struct FxItemCacheHandle
- {
- using CacheType = TCacheType;
- using KeyType = TKeyType;
- public:
- FxItemCacheHandle(TCacheType* cache, TItemType* item, TKeyType key) : Item(item), Key(key), mCache(cache) {}
- FxItemCacheHandle(const FxItemCacheHandle& other) = delete;
- FxItemCacheHandle(FxItemCacheHandle&& other)
- {
- Item = other.Item;
- Key = other.Key;
- mCache = other.mCache;
- other.Item = nullptr;
- }
- /**
- * @brief Releases the handle before the destructor is called.
- */
- FX_FORCE_INLINE void Release()
- {
- if (Item == nullptr) {
- return;
- }
- mCache->ReleaseGenericItem(Key, Item);
- }
- ~FxItemCacheHandle() { Release(); }
- TItemType* operator->() { return Item; }
- TItemType& operator*() { return *Item; }
- public:
- TItemType* Item = nullptr;
- TKeyType Key;
- private:
- CacheType* mCache;
- };
Advertisement
Add Comment
Please, Sign In to add comment