-
Notifications
You must be signed in to change notification settings - Fork 933
/
weakcache.hpp
140 lines (120 loc) · 3.75 KB
/
weakcache.hpp
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