使用unordered_map 和 双向链表实现,支持设置缓存过期时间;
其中使用到的any.h 可查询我另一篇文章 任意类型容器
#ifndef _LRU_H_
#define _LRU_H_
#include <unordered_map>
#include <mutex>
#include <vector>
#include "any.h"
template<typename KEY, size_t AllocBatch = 16>
class LruCache {
public:
struct Node {
KEY key;
Any val;
time_t expire;
Node* next;
Node* prev;
template<typename VAL>
void set(const KEY& k, const VAL& v, const int& e) {
key = k;
val = v;
expire = e;
}
void init() {
expire = 0;
next = nullptr;
prev = nullptr;
}
};
explicit LruCache(const size_t& capacity = 100, bool pre_alloc = true): m_cap(capacity){
m_head = nullptr;
m_tail = nullptr;
if(pre_alloc) {
m_available_node.resize(m_cap, nullptr);
Node* nodes = (Node*)malloc(sizeof(Node) * m_cap);
m_allocated.push_back(nodes);
for(int i = 0; i < m_cap; i++) {
m_available_node[i] = &nodes[i];
}
}
}
virtual ~LruCache(){
for(void* mem : m_allocated) {
free(mem);
}
m_allocated.clear();
}
public:
template<typename VAL>
void Put(KEY key, VAL val, int expire = 0) {
auto now = time(NULL);
auto endTime = now + expire;
if(expire == 0) {
endTime = 0;
}
std::lock_guard<std::mutex> guard(m_mutex);
if(m_map.count(key)) {
m_map[key]->val = val;
m_map[key]->expire = endTime;
deleteNode(m_map[key]);
insertHead(m_map[key]);
return;
}else if(m_map.size() >= Cap()) {
Node* del = deleteNode(m_tail);
m_available_node.push_back(del);
}else if(m_available_node.empty()) {
size_t alloc_size = Cap() - m_map.size();
if(alloc_size > AllocBatch) {
alloc_size = AllocBatch;
}
Node* nodes = (Node*)malloc(sizeof(Node) * alloc_size);
m_allocated.push_back(nodes);
for(size_t i = 0; i < alloc_size; i++) {
m_available_node.push_back(&nodes[i]);
}
}
Node* node = m_available_node.back();
m_available_node.pop_back();
node->init();
node->set(key, val, endTime);
m_map[key] = node;
insertHead(node);
// 每次插入,都检查尾部节点是否已经过期, 如果过期则立即删除
checkTailExpire(now);
}
template<typename VAL>
bool Get(KEY key, VAL& val) {
std::lock_guard<std::mutex> guard(m_mutex);
if(!m_map.count(key)) {
return false;
}
auto now = time(NULL);
if(m_map[key]->expire != 0 && m_map[key]->expire < now) {
Node* del = deleteNode(m_map[key]);
m_available_node.push_back(del);
m_map.erase(key);
return false;
}
val = m_map[key]->val.template any_cast<VAL>();
deleteNode(m_map[key]);
insertHead(m_map[key]);
// 每次操作都检查一下尾部节点是否已经过期,过期则删除,通常认为尾节点可能会最先过期
checkTailExpire(now);
return true;
}
bool Delete(KEY key) {
std::lock_guard<std::mutex> guard(m_mutex);
if(!m_map.count(key)) {
return false;
}
deleteNode(m_map[key]);
m_available_node.push_back(m_map[key]);
m_map.erase(key);
return true;
}
const size_t& Cap() const {
return m_cap;
}
const size_t& Size() const {
std::lock_guard<std::mutex> guard(m_mutex);
return m_map.size();
}
private:
Node* deleteNode(Node* node) {
if(node->prev) {
node->prev->next = node->next;
}
if(node->next) {
node->next->prev = node->prev;
}
if(node == m_head) {
m_head = node->next;
}
if(node == m_tail) {
m_tail = node->prev;
}
return node;
}
void insertHead(Node* node) {
node->next = m_head;
if(m_head) {
m_head->prev = node;
}
node->prev = nullptr;
m_head = node;
if(m_tail == nullptr) {
m_tail = node;
}
}
void checkTailExpire(const time_t& now) {
if(m_tail && m_tail->expire < now) {
Node* del = deleteNode(m_tail);
m_available_node.push_back(del);
}
}
private:
const size_t m_cap;
std::unordered_map<KEY, Node*> m_map;
struct Node* m_head;
struct Node* m_tail;
std::mutex m_mutex;
std::vector<Node*> m_available_node; // 可用的Node节点池子,用于优化频繁的创建和释放Node节点
std::vector<void*> m_allocated; // 被分配的首地址
};
#endif