#pragma once
#include <list>
#include <map>
#include <mutex>
#include <utility>
#include <shared_mutex>
// a cache which evicts the least recently used item when it is full
template <typename key_type, typename value_type>
class LruCache
{
public:
using ListType = std::list<key_type>;
using ListTypeIter = typename ListType::iterator; // 符号的结合性, 所以需要加上 typename
using MapType = std::map<key_type, std::pair<value_type, ListTypeIter>>;
LruCache() { m_capacity = 100; }
LruCache(size_t capacity) : m_capacity(capacity) { }
~LruCache() { }
size_t size() const { return m_map.size(); }
void setCapacity(size_t c) { m_capacity = c; }
size_t capacity() const { return m_capacity; }
bool contains(const key_type &key)
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_map.find(key) != m_map.end();
}
void put(const key_type &key, const value_type &value)
{
std::lock_guard<std::mutex> lock(m_mutex);
typename MapType::iterator i = m_map.find(key);
if (i == m_map.end())
{
// insert item into the cache, but first check if it is full
if (size() >= m_capacity)
{
// cache is full, evict the least recently used item
evict();
}
// insert the new item
m_list.push_front(key);
m_map[key] = std::make_pair(value, m_list.begin());
}
}
bool get(const key_type &key, value_type& value)
{
std::lock_guard<std::mutex> lock(m_mutex);
// lookup value in the cache
typename MapType::iterator iter = m_map.find(key);
if (iter == m_map.end())
{
// value not in cache
return false;
}
// return the value, but first update its place in the most
// recently used list
typename ListType::iterator j = iter->second.second;
if (j != m_list.begin())
{
// move item to the front of the most recently used list
m_list.erase(j);
m_list.push_front(key);
// update iterator in map
value = iter->second.first;
iter->second.second = m_list.begin();
}
else
{
// the item is already at the front of the most recently
// used list so just return it
value = iter->second.first;
}
return true;
}
void clear()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_map.clear();
m_list.clear();
}
private:
void evict()
{
// evict item from the end of most recently used list
typename ListType::iterator i = --m_list.end();
m_map.erase(*i);
m_list.erase(i);
}
private:
MapType m_map;
ListType m_list;
size_t m_capacity;
std::mutex m_mutex;
};