mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 00:26:39 +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
 |