mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
@@ -0,0 +1,81 @@
|
||||
import { assert } from 'chai';
|
||||
import { CircularList } from './CircularList';
|
||||
|
||||
describe('CircularList', () => {
|
||||
describe('push', () => {
|
||||
it('should push values onto the array', () => {
|
||||
const list = new CircularList<string>(5);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
list.push('3');
|
||||
list.push('4');
|
||||
list.push('5');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
assert.equal(list.get(2), '3');
|
||||
assert.equal(list.get(3), '4');
|
||||
assert.equal(list.get(4), '5');
|
||||
});
|
||||
|
||||
it('should push old values from the start out of the array when max length is reached', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
list.push('3');
|
||||
assert.equal(list.get(0), '2');
|
||||
assert.equal(list.get(1), '3');
|
||||
list.push('4');
|
||||
assert.equal(list.get(0), '3');
|
||||
assert.equal(list.get(1), '4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('maxLength', () => {
|
||||
it('should increase the size of the list', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
list.maxLength = 4;
|
||||
list.push('3');
|
||||
list.push('4');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
assert.equal(list.get(2), '3');
|
||||
assert.equal(list.get(3), '4');
|
||||
list.push('wrapped');
|
||||
assert.equal(list.get(0), '2');
|
||||
assert.equal(list.get(1), '3');
|
||||
assert.equal(list.get(2), '4');
|
||||
assert.equal(list.get(3), 'wrapped');
|
||||
});
|
||||
|
||||
it('should return the maximum length of the list', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
assert.equal(list.maxLength, 2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
assert.equal(list.maxLength, 2);
|
||||
list.push('3');
|
||||
assert.equal(list.maxLength, 2);
|
||||
list.maxLength = 4;
|
||||
assert.equal(list.maxLength, 4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('length', () => {
|
||||
it('should return the current length of the list, capped at the maximum length', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
assert.equal(list.length, 0);
|
||||
list.push('1');
|
||||
assert.equal(list.length, 1);
|
||||
list.push('2');
|
||||
assert.equal(list.length, 2);
|
||||
list.push('3');
|
||||
assert.equal(list.length, 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user