@v4fire/core
Version:
V4Fire core library
128 lines (102 loc) • 2.59 kB
text/typescript
/*!
* V4Fire Core
* https://github.com/V4Fire/Core
*
* Released under the MIT license
* https://github.com/V4Fire/Core/blob/master/LICENSE
*/
/**
* [[include:core/queue/merge/README.md]]
* @packageDocumentation
*/
import SimpleQueue from 'core/queue/simple';
import AbstractQueue from 'core/queue/interface';
import type { HashFn, InnerQueue, CreateInnerQueue } from 'core/queue/merge/interface';
export * from 'core/queue/merge/interface';
/**
* Implementation of a queue data structure with support of task merging by a specified hash function
* @typeparam T - the queue element
*/
export default class MergeQueue<T> extends AbstractQueue<T> {
/**
* Type: the internal queue to store elements
*/
readonly InnerQueue!: InnerQueue<string>;
/** @inheritDoc */
get head(): CanUndef<T> {
if (this.length === 0) {
return undefined;
}
return this.tasksMap.get(this.innerQueue.head!);
}
/** @inheritDoc */
get length(): number {
return this.innerQueue.length;
}
/**
* The internal queue to store elements
*/
protected innerQueue: this['InnerQueue'];
/**
* A map of registered tasks
*/
protected tasksMap: Map<string, T> = new Map();
/**
* A function to calculate task hashes
*/
protected readonly hashFn: HashFn<T>;
/**
* @override
* @param [hashFn] - a function to calculate task hashes
*/
constructor(hashFn?: HashFn<T>) {
super();
this.innerQueue = this.createInnerQueue();
this.hashFn = hashFn ?? Object.fastHash.bind(Object);
}
/** @inheritDoc */
push(task: T): number {
const
hash = this.hashFn(task);
if (!this.tasksMap.has(hash)) {
this.tasksMap.set(hash, task);
this.innerQueue.push(hash);
}
return this.length;
}
/** @inheritDoc */
pop(): CanUndef<T> {
if (this.length === 0) {
return;
}
const
{head} = this;
this.tasksMap.delete(this.innerQueue.head!);
this.innerQueue.shift();
return head;
}
/** @inheritDoc */
clear(): void {
if (this.length > 0) {
this.innerQueue = this.createInnerQueue();
this.tasksMap = new Map();
}
}
/** @inheritDoc */
clone(): MergeQueue<T> {
const newQueue = new MergeQueue<T>(this.hashFn);
newQueue.tasksMap = new Map(this.tasksMap);
if (this.innerQueue.clone != null) {
newQueue.innerQueue = this.innerQueue.clone();
} else {
for (const el of this.innerQueue) {
newQueue.innerQueue.push(el);
}
}
return newQueue;
}
/**
* Returns a new blank internal queue to store elements
*/
protected createInnerQueue: CreateInnerQueue<this['InnerQueue']> = () => new SimpleQueue();
}