From cf42a4cf7d6702c084f6607522e1683deaf7bca2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 24 May 2024 06:27:04 +0200 Subject: [PATCH] feat: fully implement circular buffer semantic MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/circular-buffer.ts | 41 ++++++++++++++- tests/circular-buffer.test.mjs | 92 ++++++++++++++++++++++++++++++++-- 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/src/circular-buffer.ts b/src/circular-buffer.ts index bd59b25c..46f6df5f 100644 --- a/src/circular-buffer.ts +++ b/src/circular-buffer.ts @@ -10,10 +10,11 @@ export const defaultBufferSize = 2048 * @internal */ export class CircularBuffer { - private readonly readIdx: number + private readIdx: number private writeIdx: number private items: Array private readonly maxArrayIdx: number + public size: number /** * @param size - Buffer size. @defaultValue defaultBufferSize @@ -24,9 +25,28 @@ export class CircularBuffer { this.readIdx = 0 this.writeIdx = 0 this.maxArrayIdx = size - 1 + this.size = 0 this.items = new Array(size) } + /** + * Checks whether the buffer is empty. + * + * @returns Whether the buffer is empty. + */ + public empty (): boolean { + return this.size === 0 + } + + /** + * Checks whether the buffer is full. + * + * @returns Whether the buffer is full. + */ + public full (): boolean { + return this.size === this.items.length + } + /** * Puts data into buffer. * @@ -35,6 +55,25 @@ export class CircularBuffer { public put (data: T): void { this.items[this.writeIdx] = data this.writeIdx = this.writeIdx === this.maxArrayIdx ? 0 : this.writeIdx + 1 + if (this.size < this.items.length) { + ++this.size + } + } + + /** + * Gets data from buffer. + * + * @returns Data from buffer. + */ + public get (): T | undefined { + const data = this.items[this.readIdx] + if (data == null) { + return + } + this.items[this.readIdx] = undefined + this.readIdx = this.readIdx === this.maxArrayIdx ? 0 : this.readIdx + 1 + --this.size + return data } /** diff --git a/tests/circular-buffer.test.mjs b/tests/circular-buffer.test.mjs index 804bb587..c6351eb7 100644 --- a/tests/circular-buffer.test.mjs +++ b/tests/circular-buffer.test.mjs @@ -9,15 +9,17 @@ describe('Circular buffer test suite', t => { expect(circularBuffer.readIdx).toBe(0) expect(circularBuffer.writeIdx).toBe(0) expect(circularBuffer.maxArrayIdx).toBe(defaultBufferSize - 1) + expect(circularBuffer.size).toBe(0) expect(circularBuffer.items).toBeInstanceOf(Array) expect(circularBuffer.items.length).toBe(defaultBufferSize) }) it('Verify that circular buffer size can be set at instance creation', () => { - const circularBuffer = new CircularBuffer(1000) - expect(circularBuffer.maxArrayIdx).toBe(999) + const size = 1000 + const circularBuffer = new CircularBuffer(size) + expect(circularBuffer.maxArrayIdx).toBe(size - 1) expect(circularBuffer.items).toBeInstanceOf(Array) - expect(circularBuffer.items.length).toBe(1000) + expect(circularBuffer.items.length).toBe(size) }) it('Verify that circular buffer size is valid at instance creation', () => { @@ -41,21 +43,105 @@ describe('Circular buffer test suite', t => { circularBuffer.put(1) expect(circularBuffer.items).toMatchObject([1]) expect(circularBuffer.writeIdx).toBe(1) + expect(circularBuffer.size).toBe(1) circularBuffer.put(2) expect(circularBuffer.items).toMatchObject([1, 2]) expect(circularBuffer.writeIdx).toBe(2) + expect(circularBuffer.size).toBe(2) circularBuffer.put(3) expect(circularBuffer.items).toMatchObject([1, 2, 3]) expect(circularBuffer.writeIdx).toBe(3) + expect(circularBuffer.size).toBe(3) circularBuffer.put(4) expect(circularBuffer.items).toMatchObject([1, 2, 3, 4]) expect(circularBuffer.writeIdx).toBe(0) + expect(circularBuffer.size).toBe(4) circularBuffer.put(5) expect(circularBuffer.items).toMatchObject([5, 2, 3, 4]) expect(circularBuffer.writeIdx).toBe(1) + expect(circularBuffer.size).toBe(4) circularBuffer.put(6) expect(circularBuffer.items).toMatchObject([5, 6, 3, 4]) expect(circularBuffer.writeIdx).toBe(2) + expect(circularBuffer.size).toBe(4) + }) + + it('Verify that circular buffer get() works as intended', () => { + const circularBuffer = new CircularBuffer(4) + circularBuffer.put(1) + circularBuffer.put(2) + circularBuffer.put(3) + circularBuffer.put(4) + expect(circularBuffer.get()).toBe(1) + expect(circularBuffer.readIdx).toBe(1) + expect(circularBuffer.size).toBe(3) + expect(circularBuffer.get()).toBe(2) + expect(circularBuffer.readIdx).toBe(2) + expect(circularBuffer.size).toBe(2) + circularBuffer.put(5) + circularBuffer.put(6) + expect(circularBuffer.get()).toBe(3) + expect(circularBuffer.readIdx).toBe(3) + expect(circularBuffer.size).toBe(3) + expect(circularBuffer.get()).toBe(4) + expect(circularBuffer.readIdx).toBe(0) + expect(circularBuffer.size).toBe(2) + expect(circularBuffer.get()).toBe(5) + expect(circularBuffer.readIdx).toBe(1) + expect(circularBuffer.size).toBe(1) + expect(circularBuffer.get()).toBe(6) + expect(circularBuffer.readIdx).toBe(2) + expect(circularBuffer.size).toBe(0) + expect(circularBuffer.get()).toBe(undefined) + expect(circularBuffer.readIdx).toBe(2) + expect(circularBuffer.size).toBe(0) + }) + + it('Verify that circular buffer empty() works as intended', () => { + const circularBuffer = new CircularBuffer(4) + expect(circularBuffer.empty()).toBe(true) + circularBuffer.put(1) + expect(circularBuffer.empty()).toBe(false) + circularBuffer.put(2) + expect(circularBuffer.empty()).toBe(false) + circularBuffer.put(3) + expect(circularBuffer.empty()).toBe(false) + circularBuffer.put(4) + expect(circularBuffer.empty()).toBe(false) + circularBuffer.get() + expect(circularBuffer.empty()).toBe(false) + circularBuffer.get() + expect(circularBuffer.empty()).toBe(false) + circularBuffer.get() + expect(circularBuffer.empty()).toBe(false) + circularBuffer.get() + expect(circularBuffer.empty()).toBe(true) + }) + + it('Verify that circular buffer full() works as intended', () => { + const circularBuffer = new CircularBuffer(4) + expect(circularBuffer.full()).toBe(false) + circularBuffer.put(1) + expect(circularBuffer.full()).toBe(false) + circularBuffer.put(2) + expect(circularBuffer.full()).toBe(false) + circularBuffer.put(3) + expect(circularBuffer.full()).toBe(false) + circularBuffer.put(4) + expect(circularBuffer.full()).toBe(true) + circularBuffer.get() + expect(circularBuffer.full()).toBe(false) + circularBuffer.put(5) + expect(circularBuffer.full()).toBe(true) + circularBuffer.get() + expect(circularBuffer.full()).toBe(false) + circularBuffer.get() + expect(circularBuffer.full()).toBe(false) + circularBuffer.get() + expect(circularBuffer.full()).toBe(false) + circularBuffer.get() + expect(circularBuffer.full()).toBe(false) + expect(circularBuffer.empty()).toBe(true) }) it('Verify that circular buffer toArray() works as intended', () => { -- 2.34.1