1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
#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
|