@thermopylae/lib.cache
Version:
113 lines (112 loc) • 3.76 kB
JavaScript
import { DoublyLinkedList, NEXT_SYM, PREV_SYM } from "../list/doubly-linked.js";
const BUCKET_HEADER_SYM = Symbol('BUCKET_HEADER_SYM');
class OrderedBucketList {
buckets;
constructor() {
this.buckets = new DoublyLinkedList();
}
get head() {
return this.buckets.head;
}
get tail() {
return this.buckets.tail;
}
get numberOfBuckets() {
return this.buckets.size;
}
get size() {
let items = 0;
for (const bucketHeader of this.buckets) {
items += bucketHeader.bucket.size;
}
return items;
}
has(inTheBucketId, entry) {
return entry[BUCKET_HEADER_SYM].id === inTheBucketId;
}
add(bucketId, entry) {
const bucketHeader = this.getInsertionBucket(this.buckets.head, bucketId);
OrderedBucketList.addEntryToBucketHeader(bucketHeader, entry);
}
move(_fromBucketId, toBucketId, entry) {
const currentBucketId = entry[BUCKET_HEADER_SYM].id;
if (toBucketId === currentBucketId) {
return;
}
const bucketHeader = this.getInsertionBucket(entry[BUCKET_HEADER_SYM], toBucketId);
this.removeEntryFromBucketHeader(entry);
OrderedBucketList.addEntryToBucketHeader(bucketHeader, entry);
}
remove(_fromBucketId, entry) {
this.removeEntryFromBucketHeader(entry);
}
clear() {
this.buckets.clear();
}
static getBucketId(entry) {
return entry[BUCKET_HEADER_SYM].id;
}
getInsertionBucket(startingBucketHeader, bucketId) {
if (startingBucketHeader != null) {
if (startingBucketHeader.id === bucketId) {
return startingBucketHeader;
}
let current = startingBucketHeader;
let addTo;
let appendSym;
if (bucketId > startingBucketHeader.id) {
while (current && current.id <= bucketId) {
if (current.id === bucketId) {
return current;
}
current = current[NEXT_SYM];
}
addTo = 'push';
appendSym = PREV_SYM;
}
else {
while (current && current.id >= bucketId) {
if (current.id === bucketId) {
return current;
}
current = current[PREV_SYM];
}
addTo = 'unshift';
appendSym = NEXT_SYM;
}
const newBucketHeader = {
id: bucketId,
bucket: new DoublyLinkedList(),
[PREV_SYM]: null,
[NEXT_SYM]: null
};
if (current == null) {
this.buckets[addTo](newBucketHeader);
}
else {
this.buckets.insertAfter(current[appendSym], newBucketHeader);
}
return newBucketHeader;
}
const newBucketHeader = {
id: bucketId,
bucket: new DoublyLinkedList(),
[PREV_SYM]: null,
[NEXT_SYM]: null
};
this.buckets.unshift(newBucketHeader);
return newBucketHeader;
}
removeEntryFromBucketHeader(entry) {
entry[BUCKET_HEADER_SYM].bucket.remove(entry);
if (entry[BUCKET_HEADER_SYM].bucket.empty()) {
this.buckets.remove(entry[BUCKET_HEADER_SYM]);
}
entry[BUCKET_HEADER_SYM] = undefined;
}
static addEntryToBucketHeader(bucketHeader, entry) {
bucketHeader.bucket.unshift(entry);
entry[BUCKET_HEADER_SYM] = bucketHeader;
}
}
export { OrderedBucketList, BUCKET_HEADER_SYM };