Add CircularList and basic tests

Part of #361
This commit is contained in:
Daniel Imms
2016-11-26 16:57:15 -08:00
parent d91e33ff39
commit 49b76baf3f
2 changed files with 176 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
/**
* xterm.js: xterm, in the browser
* Copyright (c) 2016, SourceLair Private Company <www.sourcelair.com> (MIT License)
*/
/**
* Represents a circular list; a list with a maximum size that wraps around when push is called,
* overriding values at the start of the list.
*/
export class CircularList<T> {
private _array: T[];
private _startIndex: number;
private _length: number;
constructor(maxLength: number) {
this._array = new Array<T>(maxLength);
this._startIndex = 0;
this._length = 0;
}
public get maxLength(): number {
return this._array.length;
}
public set maxLength(newMaxLength: number) {
// Reconstruct array, starting at index 0. Only transfer values from the
// indexes 0 to length.
let newArray = new Array<T>(newMaxLength);
for (let i = 0; i < Math.min(newMaxLength, this.length); i++) {
newArray[i] = this._array[this._getCyclicIndex(i)];
}
this._array = newArray;
this._startIndex = 0;
}
public get length(): number {
return this._length;
}
public set length(newLength: number) {
// TODO: Is this auto fill is needed or can it be
if (newLength > this._length) {
for (let i = this._length; i < newLength; i++) {
this._array[i] = undefined;
}
}
this._length = newLength;
}
public get forEach(): (callbackfn: (value: T, index: number, array: T[]) => void) => void {
return this._array.forEach;
}
/**
* Gets the value at an index.
*
* Note that for performance reasons there is no bounds checking here, the index reference is
* circular so this should always return a value and never throw.
* @param index The index of the value to get.
* @return The value corresponding to the index.
*/
public get(index: number): T {
return this._array[this._getCyclicIndex(index)];
}
/**
* Sets the value at an index.
*
* Note that for performance reasons there is no bounds checking here, the index reference is
* circular so this should always return a value and never throw.
* @param index The index to set.
* @param value The value to set.
*/
public set(index: number, value: T): void {
this._array[this._getCyclicIndex(index)] = value;
}
/**
* Pushes a new value onto the list, wrapping around to the start of the array, overriding index 0
* if the maximum length is reached.
* @param value The value to push onto the list.
*/
public push(value: T): void {
this._array[this._getCyclicIndex(this._length)] = value;
if (this._length === this.maxLength) {
this._startIndex++;
} else {
this._length++;
}
}
private _getCyclicIndex(index: number): number {
return (this._startIndex + index) % this.maxLength;
}
}