148 lines
4.5 KiB
JavaScript
148 lines
4.5 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.LfuMap = void 0;
|
|
const SizedMap_1 = require("./SizedMap");
|
|
class LfuMap extends SizedMap_1.SizedMap {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.queue = {};
|
|
this.frequencies = { 1: { index: 1, count: 0 } };
|
|
this.leastFrequent = this.frequencies[1];
|
|
}
|
|
has(key) {
|
|
const node = this.map.get(key);
|
|
if (node) {
|
|
this.removeNode(node);
|
|
this.moveToTop(node);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
get(key, _default) {
|
|
const node = this.map.get(key);
|
|
if (node) {
|
|
this.removeNode(node);
|
|
this.moveToTop(node);
|
|
return node.value;
|
|
}
|
|
return _default;
|
|
}
|
|
set(key, value) {
|
|
if (!this.limit)
|
|
return this;
|
|
let node = this.map.get(key);
|
|
if (node) {
|
|
node.value = value;
|
|
this.removeNode(node);
|
|
this.moveToTop(node);
|
|
}
|
|
else {
|
|
node = {
|
|
key: key,
|
|
value: value,
|
|
used: 0,
|
|
};
|
|
if (this.isFull()) {
|
|
super.delete(this.queuePop().key);
|
|
}
|
|
this.moveToTop(node);
|
|
this.map.set(key, node);
|
|
}
|
|
return this;
|
|
}
|
|
delete(key) {
|
|
const node = this.map.get(key);
|
|
if (node) {
|
|
this.removeNode(node);
|
|
return super.delete(key);
|
|
}
|
|
return false;
|
|
}
|
|
clear() {
|
|
this.queue = {};
|
|
this.frequencies = { 1: { index: 1, count: 0 } };
|
|
this.leastFrequent = this.frequencies[1];
|
|
super.clear();
|
|
}
|
|
initQueue(used) {
|
|
if (!this.queue[used]) {
|
|
this.queue[used] = {};
|
|
}
|
|
}
|
|
queuePop() {
|
|
const min = this.leastFrequent.index;
|
|
const node = this.queue[min].tail;
|
|
this.removeNode(node);
|
|
return node;
|
|
}
|
|
moveToTop(node) {
|
|
const used = ++node.used;
|
|
this.increaseFrequency(used);
|
|
this.initQueue(used);
|
|
node.next = this.queue[used].head;
|
|
node.previous = undefined;
|
|
if (this.queue[used].head) {
|
|
this.queue[used].head.previous = node;
|
|
}
|
|
this.queue[used].head = node;
|
|
if (!this.queue[used].tail) {
|
|
this.queue[used].tail = this.queue[used].head;
|
|
}
|
|
}
|
|
removeNode(node) {
|
|
const used = node.used;
|
|
this.decreaseFrequency(used);
|
|
this.initQueue(used);
|
|
if (node.previous) {
|
|
node.previous.next = node.next;
|
|
}
|
|
else {
|
|
this.queue[used].head = node.next;
|
|
}
|
|
if (node.next) {
|
|
node.next.previous = node.previous;
|
|
}
|
|
else {
|
|
this.queue[used].tail = node.previous;
|
|
}
|
|
}
|
|
increaseFrequency(index) {
|
|
if (!this.frequencies[index]) {
|
|
this.frequencies[index] = { index: index, count: 0 };
|
|
this.frequencies[index].next = this.frequencies[index - 1].next;
|
|
this.frequencies[index].previous = this.frequencies[index - 1].count
|
|
? this.frequencies[index - 1]
|
|
: this.frequencies[index - 1].previous;
|
|
}
|
|
if (!this.frequencies[index].count) {
|
|
if (this.frequencies[index].previous) {
|
|
this.frequencies[index].next = this.frequencies[index].previous.next;
|
|
this.frequencies[index].previous.next = this.frequencies[index];
|
|
}
|
|
if (this.frequencies[index].next) {
|
|
this.frequencies[index].previous = this.frequencies[index].next.previous;
|
|
this.frequencies[index].next.previous = this.frequencies[index];
|
|
}
|
|
}
|
|
this.frequencies[index].count++;
|
|
if (!this.leastFrequent || index < this.leastFrequent.index) {
|
|
this.leastFrequent = this.frequencies[index];
|
|
}
|
|
}
|
|
decreaseFrequency(index) {
|
|
this.frequencies[index].count--;
|
|
if (!this.frequencies[index].count) {
|
|
if (this.frequencies[index].previous) {
|
|
this.frequencies[index].previous.next = this.frequencies[index].next;
|
|
}
|
|
if (this.frequencies[index].next) {
|
|
this.frequencies[index].next.previous = this.frequencies[index].previous;
|
|
}
|
|
}
|
|
if (!this.leastFrequent || !this.leastFrequent.count) {
|
|
this.leastFrequent = this.leastFrequent.next;
|
|
}
|
|
}
|
|
}
|
|
exports.LfuMap = LfuMap;
|