All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.squarespace.cldrengine.utils.LRU Maven / Gradle / Ivy

The newest version!
package com.squarespace.cldrengine.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * Evicts the least-recently-used key when capacity is exceeded.
 *
 * Ported from @phensley/cldr-utils src/lru.ts
 */
public class LRU {

  private static final int DEFAULT_CAPACITY = 100;

  private Map> storage = new HashMap<>();
  private final Node root;
  private final int capacity;

  public LRU() {
    this(DEFAULT_CAPACITY);
  }

  public LRU(int capacity) {
    this.root = new Node<>();
    this.root.next = root;
    this.root.prev = root;
    this.capacity = capacity;
  }

  public synchronized int size() {
    return this.storage.size();
  }

  public synchronized V get(K key) {
    Node n = this.storage.get(key);
    if (n == null) {
      return null;
    }
    this.moveFront(n);
    return n.val;
  }

  public synchronized void set(K key, V val) {
    if (this.capacity == 0) {
      return;
    }

    // Key already exists, so replace its value and bump it
    // to the front. Size does not change.
    Node n = this.storage.get(key);
    if (n != null) {
      n.val = val;
      this.moveFront(n);
      return;
    }

    // The lru is full, so reuse the oldest node to keep the
    // total node allocation stable.
    if (this.storage.size() == this.capacity) {
      Node old = this.root.prev;
      if (old != null) {
        this.storage.remove(old.key);
        this.storage.put(key, old);
        old.key = key;
        old.val = val;
        this.moveFront(old);
      }
      return;
    }

    // The lru is not full, so allocate a new node.
    n = new Node<>();
    n.key = key;
    n.val = val;
    this.storage.put(key, n);
    this.insert(n, this.root);
  }

  public synchronized String toString() {
    StringBuilder buf = new StringBuilder();
    Node n = this.root.next;
    boolean nz = false;
    while (n != null && n != this.root) {
      if (nz) {
        buf.append(' ');
      }
      buf.append(n.key).append('=').append(n.val);
      n = n.next;
      nz = true;
    }
    return buf.toString();
  }

  private void moveFront(Node n) {
    this.insert(this.remove(n), this.root);
  }

  private Node insert(Node e, Node at) {
    Node n = at.next;
    at.next = e;
    e.prev = at;
    e.next = n;
    if (n != null) {
      n.prev = e;
    }
    return e;
  }

  private Node remove(Node n) {
    if (n.prev != null) {
      n.prev.next = n;
    }
    if (n.next != null) {
      n.next.prev = n.prev;
    }
    n.prev = null;
    n.next = null;
    return n;
  }

  private static class Node {
    K key;
    V val;
    Node next;
    Node prev;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy