13 #ifndef UT_LRU_CACHE_H
14 #define UT_LRU_CACHE_H
25 #include <type_traits>
26 #include <unordered_map>
49 "Pointer types need their own size function.");
68 exint(*SizeFunc)(
const V &) = UTlruGetItemSize<V>,
69 bool(*InUseFunc)(
const V &) = UTlruGetItemInUse<V>,
74 using ValueType = std::pair<const K, V>;
75 using ValueList = std::list<ValueType> ;
76 using KeyIteratorMap = std::unordered_map<K, typename ValueList::iterator>;
78 template<
typename PROXIED,
typename TYPE>
81 ValueList myValueList;
82 KeyIteratorMap myKeyMap;
85 std::function<exint(const V &)> mySizeFunc;
86 std::function<bool(const V &)> myInUseFunc;
92 template<
typename PROXIED,
typename TYPE>
94 public std::iterator<std::bidirectional_iterator_tag, TYPE>
97 typename std::iterator<std::bidirectional_iterator_tag, TYPE>;
98 using proxied_iterator = PROXIED;
107 other.myLock->readLock();
109 myLock = other.myLock;
114 myIt = std::move(other.myIt);
115 other.myIt = proxied_iterator();
116 myLock = other.myLock;
117 other.myLock =
nullptr;
122 other.myLock->readLock();
124 myLock = other.myLock;
130 myIt = std::move(other.myIt);
131 other.myIt = proxied_iterator();
132 myLock = other.myLock;
133 other.myLock =
nullptr;
141 myLock->readUnlock();
152 return myIt == other.myIt;
156 return myIt != other.myIt;
163 myIt(it), myLock(lock) { }
166 proxied_iterator myIt;
172 using iterator = iterator_base<typename ValueList::iterator, std::pair<const K, V>>;
175 using const_iterator = iterator_base<typename ValueList::const_iterator, const std::pair<const K, V>>;
185 mySizeFunc(SizeFunc),
186 myInUseFunc(InUseFunc),
198 if (max_size >= myMaxSize)
200 myMaxSize = max_size;
204 myMaxSize = max_size;
211 myLock->writeUnlock();
228 myLock->readUnlock();
241 myLock->readUnlock();
252 bool found = (myKeyMap.find(key) != myKeyMap.end());
255 myLock->readUnlock();
270 auto itK = myKeyMap.find(key);
271 if (itK == myKeyMap.end())
274 myLock->readUnlock();
275 return iterator(myValueList.end(),
nullptr);
279 if (itK->second != myValueList.begin())
281 myValueList.splice(itK->second, myValueList, myValueList.begin());
282 itK->second = myValueList.begin();
285 return iterator(itK->second, myLock);
294 std::pair<iterator, bool>
306 std::pair<iterator, bool>
result;
307 auto itK = myKeyMap.find(key);
308 if (itK != myKeyMap.end() && !evict)
312 result = std::make_pair(
iterator(itK->second, myLock),
false);
316 if (itK != myKeyMap.end())
320 myCurrentSize -= mySizeFunc((itK->second)->second);
321 myCurrentSize += mySizeFunc(
value);
328 myValueList.splice(itK->second, myValueList,
329 myValueList.begin());
331 myValueList.begin()->second = std::move(
value);
332 itK->second = myValueList.begin();
334 result = std::make_pair(
iterator(itK->second, myLock),
true);
338 myCurrentSize += mySizeFunc(
value);
342 myValueList.push_front(std::make_pair(key, std::move(
value)));
343 myKeyMap.insert(std::make_pair(key, myValueList.begin()));
345 result = std::make_pair(
iterator(myValueList.begin(), myLock),
351 myLock->writeUnlock();
361 bool updated =
false;
365 auto itK = myKeyMap.find(key);
366 if (itK != myKeyMap.end())
368 myCurrentSize -= mySizeFunc((itK->second)->second);
369 myValueList.erase(itK->second);
375 myLock->writeUnlock();
385 bool updated =
false;
389 auto itK = myKeyMap.find(key);
390 if (itK != myKeyMap.end())
392 myCurrentSize -= mySizeFunc((itK->second)->second);
395 value = std::move((itK->second)->second);
397 myValueList.erase(itK->second);
403 myLock->writeUnlock();
411 if (myLock) myLock->writeLock();
417 if (myLock) myLock->writeUnlock();
423 if (myLock) myLock->readLock();
424 return iterator(myValueList.begin(), myLock);
431 return iterator(myValueList.end(),
nullptr);
437 if (myLock) myLock->readLock();
452 void prune(
typename ValueList::iterator *itSkipV =
nullptr)
454 for (
auto ritV = myValueList.rbegin();
455 myCurrentSize > myMaxSize && ritV != myValueList.rend(); ++ritV)
457 if ((itSkipV && ritV.base() == *itSkipV) ||
458 myInUseFunc(ritV->second))
463 myCurrentSize -= mySizeFunc(ritV->second);
465 auto itK = myKeyMap.find(ritV->first);
469 auto itV = myValueList.erase(std::prev(ritV.base()));
470 ritV =
typename ValueList::reverse_iterator(itV);
iterator_base(proxied_iterator it, L *lock)
std::pair< iterator, bool > insert(const K &key, V &&value, bool evict=false)
bool steal(const K &key, V &&value)
GLenum const void GLuint GLint reference
iterator find(const K &key)
bool UTlruGetItemInUse(const V &)
bool operator!=(const iterator_base &other) const
iterator_base< typename ValueList::iterator, std::pair< const cl_mem, ut_clBuffer >> iterator
A iterator pointing to mutable values.
iterator_base< typename ValueList::const_iterator, const std::pair< const cl_mem, ut_clBuffer >> const_iterator
A const iterator pointing to immutable values.
exint currentSize() const
iterator begin()
Returns an iterator to the front-most item in the LRU cache.
iterator_base & operator=(iterator_base &&other)
exint UTlruGetItemSize(const V &)
iterator_base(iterator_base &&other)
bool operator==(const iterator_base &other) const
iterator end()
Returns an iterator to the end of the LRU list.
pointer operator->() const
exint maxSize() const
Returns the current maximum size of the cache.
UT_LRUCache(exint max_size=SYS_EXINT_MAX)
void setMaxSize(exint max_size)
bool contains(const K &key) const
const_iterator begin() const
Returns a const iterator to the front-most item in the LRU cache.
const_iterator end() const
Returns a const iterator to the end of the LRU list.
GLsizei const GLfloat * value
exint count() const
Returns the number of items in the cache.
iterator_base(const iterator_base &other)
iterator_base & operator=(const iterator_base &other)
reference operator*() const
friend class iterator_base
iterator_base & operator++()
void clear()
Clears the cache completely.
iterator_base & operator--()