123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- 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();
- }
- }
|