mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-27 03:26:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			140 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OPENMW_COMPONENTS_WEAKCACHE_HPP
 | |
| #define OPENMW_COMPONENTS_WEAKCACHE_HPP
 | |
| 
 | |
| #include <memory>
 | |
| #include <unordered_map>
 | |
| #include <vector>
 | |
| 
 | |
| namespace Misc
 | |
| {
 | |
|     /// \class WeakCache
 | |
|     /// Provides a container to weakly store pointers to shared data.
 | |
|     template <typename Key, typename T>
 | |
|     class WeakCache
 | |
|     {
 | |
|     public:
 | |
|         using WeakPtr = std::weak_ptr<T>;
 | |
|         using StrongPtr = std::shared_ptr<T>;
 | |
|         using Map = std::unordered_map<Key, WeakPtr>;
 | |
| 
 | |
|         class iterator
 | |
|         {
 | |
|         public:
 | |
|             iterator(WeakCache* cache, typename Map::iterator current, typename Map::iterator end);
 | |
|             iterator& operator++();
 | |
|             bool operator==(const iterator& other) const;
 | |
|             bool operator!=(const iterator& other) const;
 | |
|             StrongPtr operator*();
 | |
| 
 | |
|         private:
 | |
|             WeakCache* mCache;
 | |
|             typename Map::iterator mCurrent, mEnd;
 | |
|             StrongPtr mPtr;
 | |
|         };
 | |
| 
 | |
|         /// Stores a weak pointer to the item.
 | |
|         void insert(Key key, StrongPtr value, bool prune = true);
 | |
| 
 | |
|         /// Retrieves the item associated with the key.
 | |
|         /// \return An item or null.
 | |
|         StrongPtr get(Key key);
 | |
| 
 | |
|         iterator begin();
 | |
|         iterator end();
 | |
| 
 | |
|         /// Removes known invalid entries
 | |
|         void prune();
 | |
| 
 | |
|     private:
 | |
|         Map mData;
 | |
|         std::vector<Key> mDirty;
 | |
|     };
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     WeakCache<Key, T>::iterator::iterator(WeakCache* cache, typename Map::iterator current, typename Map::iterator end)
 | |
|         : mCache(cache)
 | |
|         , mCurrent(current)
 | |
|         , mEnd(end)
 | |
|     {
 | |
|         // Move to 1st available valid item
 | |
|         for (; mCurrent != mEnd; ++mCurrent)
 | |
|         {
 | |
|             mPtr = mCurrent->second.lock();
 | |
|             if (mPtr)
 | |
|                 break;
 | |
|             else
 | |
|                 mCache->mDirty.push_back(mCurrent->first);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     typename WeakCache<Key, T>::iterator& WeakCache<Key, T>::iterator::operator++()
 | |
|     {
 | |
|         auto next = mCurrent;
 | |
|         ++next;
 | |
|         return *this = iterator(mCache, next, mEnd);
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     bool WeakCache<Key, T>::iterator::operator==(const iterator& other) const
 | |
|     {
 | |
|         return mCurrent == other.mCurrent;
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     bool WeakCache<Key, T>::iterator::operator!=(const iterator& other) const
 | |
|     {
 | |
|         return !(*this == other);
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     typename WeakCache<Key, T>::StrongPtr WeakCache<Key, T>::iterator::operator*()
 | |
|     {
 | |
|         return mPtr;
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     void WeakCache<Key, T>::insert(Key key, StrongPtr value, bool shouldPrune)
 | |
|     {
 | |
|         mData[key] = WeakPtr(value);
 | |
|         if (shouldPrune)
 | |
|             prune();
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     typename WeakCache<Key, T>::StrongPtr WeakCache<Key, T>::get(Key key)
 | |
|     {
 | |
|         auto searchIt = mData.find(key);
 | |
|         if (searchIt != mData.end())
 | |
|             return searchIt->second.lock();
 | |
|         else
 | |
|             return StrongPtr();
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     typename WeakCache<Key, T>::iterator WeakCache<Key, T>::begin()
 | |
|     {
 | |
|         return iterator(this, mData.begin(), mData.end());
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     typename WeakCache<Key, T>::iterator WeakCache<Key, T>::end()
 | |
|     {
 | |
|         return iterator(this, mData.end(), mData.end());
 | |
|     }
 | |
| 
 | |
|     template <typename Key, typename T>
 | |
|     void WeakCache<Key, T>::prune()
 | |
|     {
 | |
|         // Remove empty entries
 | |
|         for (auto& key : mDirty)
 | |
|         {
 | |
|             auto it = mData.find(key);
 | |
|             if (it != mData.end() && it->second.use_count() == 0)
 | |
|                 mData.erase(it);
 | |
|         }
 | |
|         mDirty.clear();
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif
 |