diff --git a/src/utils/CircularList.test.ts b/src/utils/CircularList.test.ts index 4a89aa3c..3b2520ab 100644 --- a/src/utils/CircularList.test.ts +++ b/src/utils/CircularList.test.ts @@ -78,4 +78,54 @@ describe('CircularList', () => { assert.equal(list.length, 2); }); }); + + describe('splice', () => { + it('should delete items', () => { + const list = new CircularList(2); + list.push('1'); + list.push('2'); + list.splice(0, 1); + assert.equal(list.length, 1); + assert.equal(list.get(0), '2'); + list.push('3'); + list.splice(1, 1); + assert.equal(list.length, 1); + assert.equal(list.get(0), '2'); + }); + + it('should insert items', () => { + const list = new CircularList(2); + list.push('1'); + list.splice(0, 0, '2'); + assert.equal(list.length, 2); + assert.equal(list.get(0), '2'); + assert.equal(list.get(1), '1'); + list.splice(1, 0, '3'); + assert.equal(list.length, 2); + assert.equal(list.get(0), '3'); + assert.equal(list.get(1), '1'); + }); + + it('should delete items then insert items', () => { + const list = new CircularList(3); + list.push('1'); + list.push('2'); + list.splice(0, 1, '3', '4'); + assert.equal(list.length, 3); + assert.equal(list.get(0), '3'); + assert.equal(list.get(1), '4'); + assert.equal(list.get(2), '2'); + }); + + it('should wrap the array correctly when more items are inserted than deleted', () => { + const list = new CircularList(3); + list.push('1'); + list.push('2'); + list.splice(1, 0, '3', '4'); + assert.equal(list.length, 3); + assert.equal(list.get(0), '3'); + assert.equal(list.get(1), '4'); + assert.equal(list.get(2), '2'); + }); + }); }); diff --git a/src/utils/CircularList.ts b/src/utils/CircularList.ts index 51da0c6d..a131bcbd 100644 --- a/src/utils/CircularList.ts +++ b/src/utils/CircularList.ts @@ -89,6 +89,35 @@ export class CircularList { } } + public pop(): T { + return this._array[this._getCyclicIndex(this._length-- - 1)]; + } + + // TODO: Warn there's no error handling and that this is a slow operation + public splice(start: number, deleteCount: number, ...items: T[]) { + if (deleteCount) { + for (let i = start; i < this._length - deleteCount; i++) { + this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)]; + } + this._length -= deleteCount; + } + if (items && items.length) { + for (let i = this._length - 1; i >= start; i--) { + this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)]; + } + for (let i = 0; i < items.length; i++) { + this._array[this._getCyclicIndex(start + i)] = items[i]; + } + + if (this._length + items.length > this.maxLength) { + this._startIndex += (this._length + items.length) - this.maxLength; + this._length = this.maxLength; + } else { + this._length += items.length; + } + } + } + private _getCyclicIndex(index: number): number { return (this._startIndex + index) % this.maxLength; }