mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-19 08:50:29 +00:00
120 lines
2.9 KiB
TypeScript
120 lines
2.9 KiB
TypeScript
export class CircularQueue<T> {
|
|
private startIndex: number;
|
|
private endIndex: number;
|
|
private _data: T[];
|
|
private _size: number;
|
|
private _capacity: number;
|
|
|
|
constructor(
|
|
size: number,
|
|
) {
|
|
// See the Mozilla documentation on sparse arrays (*not* undefined values)
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays
|
|
this._data = new Array<T>(size);
|
|
this.startIndex = 0;
|
|
this.endIndex = 0;
|
|
this._size = 0;
|
|
this._capacity = size;
|
|
}
|
|
|
|
size = (): number => this._size;
|
|
|
|
get = (index: number): T | undefined => {
|
|
if (index < 0 || index >= this._size) {
|
|
return undefined;
|
|
}
|
|
const actualIndex = (this.startIndex + index) % this._capacity;
|
|
return this._data[actualIndex];
|
|
};
|
|
|
|
appendWithSorting = (
|
|
data: T,
|
|
sortingCallback: (a: T, b: T) => number
|
|
) => {
|
|
if (this._size === 0) {
|
|
this._data[this.startIndex] = data;
|
|
this._size = 1;
|
|
this.endIndex = this.startIndex;
|
|
return;
|
|
}
|
|
|
|
const lastItem = this.get(this._size - 1);
|
|
const isAlreadyInOrder = lastItem && sortingCallback(lastItem, data) <= 0;
|
|
|
|
if (this._size < this._capacity) {
|
|
this.endIndex = (this.endIndex + 1) % this._capacity;
|
|
this._data[this.endIndex] = data;
|
|
this._size++;
|
|
} else {
|
|
this.startIndex = (this.startIndex + 1) % this._capacity;
|
|
this.endIndex = (this.endIndex + 1) % this._capacity;
|
|
this._data[this.endIndex] = data;
|
|
}
|
|
|
|
if (!isAlreadyInOrder) {
|
|
this.sortData(sortingCallback);
|
|
}
|
|
}
|
|
|
|
popFront = () => {
|
|
if (this._size === 0) {
|
|
return;
|
|
}
|
|
|
|
this._data[this.startIndex] = undefined as any;
|
|
if (this._size === 1) {
|
|
this._size = 0;
|
|
this.startIndex = 0;
|
|
this.endIndex = 0;
|
|
} else {
|
|
this.startIndex = (this.startIndex + 1) % this._capacity;
|
|
this._size--;
|
|
}
|
|
}
|
|
|
|
binarySearch = <K>(
|
|
searchKey: K,
|
|
keyExtractor: (item: T) => K
|
|
): T | undefined => {
|
|
if (this._size === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
let left = 0;
|
|
let right = this._size - 1;
|
|
|
|
while (left <= right) {
|
|
const mid = Math.floor((left + right) / 2);
|
|
const midItem = this.get(mid)!;
|
|
const midKey = keyExtractor(midItem);
|
|
|
|
if (midKey === searchKey) {
|
|
return midItem;
|
|
} else if (midKey < searchKey) {
|
|
left = mid + 1;
|
|
} else {
|
|
right = mid - 1;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
private sortData = (sortingCallback: (a: T, b: T) => number) => {
|
|
const items: T[] = [];
|
|
for (let i = 0; i < this._size; i++) {
|
|
const item = this.get(i);
|
|
if (item !== undefined) {
|
|
items.push(item);
|
|
}
|
|
}
|
|
|
|
items.sort(sortingCallback);
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
const actualIndex = (this.startIndex + i) % this._capacity;
|
|
this._data[actualIndex] = items[i];
|
|
}
|
|
};
|
|
}
|