UNPKG

@thermopylae/lib.cache

Version:
113 lines (112 loc) 3.76 kB
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 };