MMKV中的简单LRU缓存(LRUCache)
LRU(Least recently used)是一种缓存更新策略,即当缓存数目达到最大容量、或者某个条件时,移除掉最近最少使用的元素。微信前不久开源了一个客户端Key-Value存储库MMKV https://github.com/Tencent/MMKV ,其中实现了这样一个十分精简的LRU缓存(LRUCache类)。
LRUCache实现原理介绍
下面是代码及注释。
MMKV的实现
代码就贴这里,相信看一遍就很容易明白
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
| #import <list>
#import <unordered_map>
template <typename Key_t, typename Value_t> class LRUCache { size_t m_capacity; std::list<std::pair<Key_t, Value_t>> m_list; std::unordered_map<Key_t, typename decltype(m_list)::iterator> m_map; public: LRUCache(size_t capacity) : m_capacity(capacity) {} size_t size() const { return m_map.size(); } size_t capacity() const { return m_capacity; } bool contains(const Key_t &key) const { return m_map.find(key) != m_map.end(); } void clear() { m_list.clear(); m_map.clear(); } void insert(const Key_t &key, const Value_t &value) { auto itr = m_map.find(key); if (itr != m_map.end()) { m_list.splice(m_list.begin(), m_list, itr->second); itr->second->second = value; } else { if (m_map.size() == m_capacity) { m_map.erase(m_list.back().first); m_list.pop_back(); } m_list.push_front(std::make_pair(key, value)); m_map.insert(std::make_pair(key, m_list.begin())); } } Value_t *get(const Key_t &key) { auto itr = m_map.find(key); if (itr != m_map.end()) { m_list.splice(m_list.begin(), m_list, itr->second); return &itr->second->second; } return nullptr; } void forEach(std::function<void(Key_t&,Value_t&)> callback){ for(auto & item : m_list){ callback(item.first,item.second); } } };
|
增加打印方法
上面增加了一个打印所有元素的辅助方法forEach
1 2 3 4 5
| void forEach(std::function<void(Key_t&,Value_t&)> callback){ for(auto & item : m_list){ callback(item.first,item.second); } }
|
传入一个lambda表达式就可以打印了。
测试例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| LRUCache<string, int> cache(5); cache.insert("a",1); cache.insert("b",2); cache.insert("c",3); cache.insert("d",4); cache.insert("e",5); cache.forEach([](string& key,int& value){ NSLog(@"%s - %d",key.c_str(),value); }); NSLog(@">> after insert 6"); cache.insert("f",6); cache.forEach([](string& key,int& value){ NSLog(@"%s - %d",key.c_str(),value); }); NSLog(@">> after get d"); cache.get("d"); cache.forEach([](string& key,int& value){ NSLog(@"%s - %d",key.c_str(),value); });
|
输出如下:
其他缓存策略
https://en.wikipedia.org/wiki/Cache_replacement_policies
参考
https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
LeetCode 中就有个类似的题目 https://leetcode.com/problems/lru-cache/description/ 可以练习一下。