+++ /dev/null
-/**
- * Copyright (c) 2017 The xterm.js authors. All rights reserved.
- * @license MIT
- */
-
-interface ILinkedListNode<T> {
- prev: ILinkedListNode<T> | null;
- next: ILinkedListNode<T> | null;
- key: number | null;
- value: T | null;
-}
-
-export class LRUMap<T> {
- private _map: { [key: number]: ILinkedListNode<T> } = {};
- private _head: ILinkedListNode<T> | null = null;
- private _tail: ILinkedListNode<T> | null = null;
- private _nodePool: ILinkedListNode<T>[] = [];
- public size: number = 0;
-
- constructor(public capacity: number) { }
-
- private _unlinkNode(node: ILinkedListNode<T>): void {
- const prev = node.prev;
- const next = node.next;
- if (node === this._head) {
- this._head = next;
- }
- if (node === this._tail) {
- this._tail = prev;
- }
- if (prev !== null) {
- prev.next = next;
- }
- if (next !== null) {
- next.prev = prev;
- }
- }
-
- private _appendNode(node: ILinkedListNode<T>): void {
- const tail = this._tail;
- if (tail !== null) {
- tail.next = node;
- }
- node.prev = tail;
- node.next = null;
- this._tail = node;
- if (this._head === null) {
- this._head = node;
- }
- }
-
- /**
- * Preallocate a bunch of linked-list nodes. Allocating these nodes ahead of time means that
- * they're more likely to live next to each other in memory, which seems to improve performance.
- *
- * Each empty object only consumes about 60 bytes of memory, so this is pretty cheap, even for
- * large maps.
- */
- public prealloc(count: number): void {
- const nodePool = this._nodePool;
- for (let i = 0; i < count; i++) {
- nodePool.push({
- prev: null,
- next: null,
- key: null,
- value: null
- });
- }
- }
-
- public get(key: number): T | null {
- // This is unsafe: We're assuming our keyspace doesn't overlap with Object.prototype. However,
- // it's faster than calling hasOwnProperty, and in our case, it would never overlap.
- const node = this._map[key];
- if (node !== undefined) {
- this._unlinkNode(node);
- this._appendNode(node);
- return node.value;
- }
- return null;
- }
-
- /**
- * Gets a value from a key without marking it as the most recently used item.
- */
- public peekValue(key: number): T | null {
- const node = this._map[key];
- if (node !== undefined) {
- return node.value;
- }
- return null;
- }
-
- public peek(): T | null {
- const head = this._head;
- return head === null ? null : head.value;
- }
-
- public set(key: number, value: T): void {
- // This is unsafe: See note above.
- let node = this._map[key];
- if (node !== undefined) {
- // already exists, we just need to mutate it and move it to the end of the list
- node = this._map[key];
- this._unlinkNode(node);
- node.value = value;
- } else if (this.size >= this.capacity) {
- // we're out of space: recycle the head node, move it to the tail
- node = this._head!;
- this._unlinkNode(node);
- delete this._map[node.key!];
- node.key = key;
- node.value = value;
- this._map[key] = node;
- } else {
- // make a new element
- const nodePool = this._nodePool;
- if (nodePool.length > 0) {
- // use a preallocated node if we can
- node = nodePool.pop()!;
- node.key = key;
- node.value = value;
- } else {
- node = {
- prev: null,
- next: null,
- key,
- value
- };
- }
- this._map[key] = node;
- this.size++;
- }
- this._appendNode(node);
- }
-}