LruCache结合Any容器类型实现任意类型缓存

使用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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值