Lam NguyenLibrary

Library · Databases · cache eviction

LRU Cache

Code ↗
#pragma once
#include "eviction_cache.h"

class LRUCache : public EvictionCache {
private:
    struct Node {
        int key;
        int value;
        Node* prev;
        Node* next;
        Node() : key(-1), value(-1), prev(nullptr), next(nullptr) {}
        Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
    };

    Node* head;
    Node* tail;
    int capacity;
    unordered_map<int, Node*> nodeMap;

    void moveToHead(Node* node) {
        if (node->prev != nullptr) node->prev->next = node->next;
        if (node->next != nullptr) node->next->prev = node->prev;

        Node* nextHead = head->next;
        head->next = node;
        node->prev = head;
        node->next = nextHead;
        if (nextHead != nullptr) nextHead->prev = node;
    }

    Page evict() {
        if ((int)nodeMap.size() <= capacity) return {};

        Node* removeNode = tail->prev;
        if (removeNode == head) return {};

        Node* prevRemoveNode = removeNode->prev;
        prevRemoveNode->next = tail;
        tail->prev = prevRemoveNode;

        Page evicted{removeNode->key, removeNode->value, true};
        nodeMap.erase(removeNode->key);
        delete removeNode;
        return evicted;
    }

public:
    LRUCache(int cap) : capacity(cap) {
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
    }

    ~LRUCache() override {
        Node* cur = head;
        while (cur != nullptr) {
            Node* nxt = cur->next;
            delete cur;
            cur = nxt;
        }
    }

    string name() const override { return "LRU"; }

    Page get(int key) override {
        if (!nodeMap.count(key)) return {};
        moveToHead(nodeMap[key]);
        return {key, nodeMap[key]->value, true};
    }

    Page put(int key, int value) override {
        if (nodeMap.count(key)) {
            nodeMap[key]->value = value;
            moveToHead(nodeMap[key]);
        } else {
            Node* newNode = new Node(key, value);
            nodeMap[key] = newNode;
            moveToHead(newNode);
        }
        return evict();
    }
};