UNPKG

zrender

Version:

A lightweight graphic library providing 2d draw for Apache ECharts

175 lines (145 loc) 3.5 kB
import { Dictionary } from './types'; // Simple LRU cache use doubly linked list // @module zrender/core/LRU export class Entry<T> { value: T key: string | number next: Entry<T> prev: Entry<T> constructor(val: T) { this.value = val; } } /** * Simple double linked list. Compared with array, it has O(1) remove operation. * @constructor */ export class LinkedList<T> { head: Entry<T> tail: Entry<T> private _len = 0 /** * Insert a new value at the tail */ insert(val: T): Entry<T> { const entry = new Entry(val); this.insertEntry(entry); return entry; } /** * Insert an entry at the tail */ insertEntry(entry: Entry<T>) { if (!this.head) { this.head = this.tail = entry; } else { this.tail.next = entry; entry.prev = this.tail; entry.next = null; this.tail = entry; } this._len++; } /** * Remove entry. */ remove(entry: Entry<T>) { const prev = entry.prev; const next = entry.next; if (prev) { prev.next = next; } else { // Is head this.head = next; } if (next) { next.prev = prev; } else { // Is tail this.tail = prev; } entry.next = entry.prev = null; this._len--; } /** * Get length */ len(): number { return this._len; } /** * Clear list */ clear() { this.head = this.tail = null; this._len = 0; } } /** * LRU Cache */ export default class LRU<T> { private _list = new LinkedList<T>() private _maxSize = 10 private _lastRemovedEntry: Entry<T> private _map: Dictionary<Entry<T>> = {} constructor(maxSize: number) { this._maxSize = maxSize; } /** * @return Removed value */ put(key: string | number, value: T): T { const list = this._list; const map = this._map; let removed = null; if (map[key] == null) { const len = list.len(); // Reuse last removed entry let entry = this._lastRemovedEntry; if (len >= this._maxSize && len > 0) { // Remove the least recently used const leastUsedEntry = list.head; list.remove(leastUsedEntry); delete map[leastUsedEntry.key]; removed = leastUsedEntry.value; this._lastRemovedEntry = leastUsedEntry; } if (entry) { entry.value = value; } else { entry = new Entry(value); } entry.key = key; list.insertEntry(entry); map[key] = entry; } return removed; } get(key: string | number): T { const entry = this._map[key]; const list = this._list; if (entry != null) { // Put the latest used entry in the tail if (entry !== list.tail) { list.remove(entry); list.insertEntry(entry); } return entry.value; } } /** * Clear the cache */ clear() { this._list.clear(); this._map = {}; } len() { return this._list.len(); } }