refactor: factor out fixed queue common code in an abstract class
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 6 Jul 2024 23:28:47 +0000 (01:28 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 6 Jul 2024 23:28:47 +0000 (01:28 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
src/abstract-fixed-queue.ts [new file with mode: 0644]
src/fixed-priority-queue.ts
src/fixed-queue.ts
tests/fixed-priority-queue.test.mjs

diff --git a/src/abstract-fixed-queue.ts b/src/abstract-fixed-queue.ts
new file mode 100644 (file)
index 0000000..eee066d
--- /dev/null
@@ -0,0 +1,118 @@
+import {
+  defaultQueueSize,
+  type FixedQueueNode,
+  type IFixedQueue,
+} from './utility-types.js'
+
+/**
+ * Base fixed queue class
+ * @typeParam T - Type of fixed queue data.
+ * @internal
+ */
+export abstract class AbstractFixedQueue<T> implements IFixedQueue<T> {
+  protected start!: number
+  /** @inheritdoc */
+  public readonly capacity: number
+  /** @inheritdoc */
+  public size!: number
+  /** @inheritdoc */
+  public nodeArray: FixedQueueNode<T>[]
+
+  /**
+   * Constructs a fixed queue.
+   * @param size - Fixed queue size. @defaultValue defaultQueueSize
+   * @returns IFixedQueue.
+   */
+  constructor (size: number = defaultQueueSize) {
+    this.checkSize(size)
+    this.capacity = size
+    this.nodeArray = new Array<FixedQueueNode<T>>(this.capacity)
+    this.clear()
+  }
+
+  /** @inheritdoc */
+  public empty (): boolean {
+    return this.size === 0
+  }
+
+  /** @inheritdoc */
+  public full (): boolean {
+    return this.size === this.capacity
+  }
+
+  /** @inheritdoc */
+  public abstract enqueue (data: T, priority?: number): number
+
+  /** @inheritdoc */
+  public get (index: number): T | undefined {
+    if (this.empty() || index >= this.size) {
+      return undefined
+    }
+    index += this.start
+    if (index >= this.capacity) {
+      index -= this.capacity
+    }
+    return this.nodeArray[index].data
+  }
+
+  /** @inheritdoc */
+  public dequeue (): T | undefined {
+    if (this.empty()) {
+      return undefined
+    }
+    const index = this.start
+    --this.size
+    ++this.start
+    if (this.start === this.capacity) {
+      this.start = 0
+    }
+    return this.nodeArray[index].data
+  }
+
+  /** @inheritdoc */
+  public clear (): void {
+    this.start = 0
+    this.size = 0
+  }
+
+  /** @inheritdoc */
+  public [Symbol.iterator] (): Iterator<T> {
+    let index = this.start
+    let i = 0
+    return {
+      next: () => {
+        if (i >= this.size) {
+          return {
+            value: undefined,
+            done: true,
+          }
+        }
+        const value = this.nodeArray[index].data
+        ++index
+        ++i
+        if (index === this.capacity) {
+          index = 0
+        }
+        return {
+          value,
+          done: false,
+        }
+      },
+    }
+  }
+
+  /**
+   * Checks the fixed queue size.
+   * @param size - Queue size.
+   */
+  private checkSize (size: number): void {
+    if (!Number.isSafeInteger(size)) {
+      throw new TypeError(
+        `Invalid fixed queue size: '${size.toString()}' is not an integer`
+      )
+    }
+    if (size < 0) {
+      throw new RangeError(`Invalid fixed queue size: ${size.toString()} < 0`)
+    }
+  }
+}
index 1ce6bbc42fa193d5e2436e3d8733b554a0f260de..6c899283005d83be751bcd741890f2a615b51d72 100644 (file)
@@ -1,45 +1,14 @@
-import {
-  defaultQueueSize,
-  type FixedQueueNode,
-  type IFixedQueue,
-} from './utility-types.js'
+import { AbstractFixedQueue } from './abstract-fixed-queue.js'
+import type { IFixedQueue } from './utility-types.js'
 
 /**
  * Fixed priority queue.
  * @typeParam T - Type of fixed priority queue data.
  * @internal
  */
-export class FixedPriorityQueue<T> implements IFixedQueue<T> {
-  private start!: number
-  /** @inheritdoc */
-  public readonly capacity: number
-  /** @inheritdoc */
-  public size!: number
-  /** @inheritdoc */
-  public nodeArray: FixedQueueNode<T>[]
-
-  /**
-   * Constructs a fixed priority queue.
-   * @param size - Fixed priority queue size. @defaultValue defaultQueueSize
-   * @returns FixedPriorityQueue.
-   */
-  constructor (size: number = defaultQueueSize) {
-    this.checkSize(size)
-    this.capacity = size
-    this.nodeArray = new Array<FixedQueueNode<T>>(this.capacity)
-    this.clear()
-  }
-
-  /** @inheritdoc */
-  public empty (): boolean {
-    return this.size === 0
-  }
-
-  /** @inheritdoc */
-  public full (): boolean {
-    return this.size === this.capacity
-  }
-
+export class FixedPriorityQueue<T>
+  extends AbstractFixedQueue<T>
+  implements IFixedQueue<T> {
   /** @inheritdoc */
   public enqueue (data: T, priority?: number): number {
     if (this.full()) {
@@ -69,79 +38,4 @@ export class FixedPriorityQueue<T> implements IFixedQueue<T> {
     }
     return ++this.size
   }
-
-  /** @inheritdoc */
-  public get (index: number): T | undefined {
-    if (this.empty() || index >= this.size) {
-      return undefined
-    }
-    index += this.start
-    if (index >= this.capacity) {
-      index -= this.capacity
-    }
-    return this.nodeArray[index].data
-  }
-
-  /** @inheritdoc */
-  public dequeue (): T | undefined {
-    if (this.empty()) {
-      return undefined
-    }
-    const index = this.start
-    --this.size
-    ++this.start
-    if (this.start === this.capacity) {
-      this.start = 0
-    }
-    return this.nodeArray[index].data
-  }
-
-  /** @inheritdoc */
-  public clear (): void {
-    this.start = 0
-    this.size = 0
-  }
-
-  /** @inheritdoc */
-  public [Symbol.iterator] (): Iterator<T> {
-    let index = this.start
-    let i = 0
-    return {
-      next: () => {
-        if (i >= this.size) {
-          return {
-            value: undefined,
-            done: true,
-          }
-        }
-        const value = this.nodeArray[index].data
-        ++index
-        ++i
-        if (index === this.capacity) {
-          index = 0
-        }
-        return {
-          value,
-          done: false,
-        }
-      },
-    }
-  }
-
-  /**
-   * Checks the fixed queue size.
-   * @param size - Queue size.
-   */
-  private checkSize (size: number): void {
-    if (!Number.isSafeInteger(size)) {
-      throw new TypeError(
-        `Invalid fixed priority queue size: '${size.toString()}' is not an integer`
-      )
-    }
-    if (size < 0) {
-      throw new RangeError(
-        `Invalid fixed priority queue size: ${size.toString()} < 0`
-      )
-    }
-  }
 }
index 985acf504d7012e8a4d912e80b2b6f309f0a7327..42034e2fc887c34b461c7303f8049a2b0351d32f 100644 (file)
@@ -1,45 +1,14 @@
-import {
-  defaultQueueSize,
-  type FixedQueueNode,
-  type IFixedQueue,
-} from './utility-types.js'
+import { AbstractFixedQueue } from './abstract-fixed-queue.js'
+import type { IFixedQueue } from './utility-types.js'
 
 /**
  * Fixed queue.
  * @typeParam T - Type of fixed queue data.
  * @internal
  */
-export class FixedQueue<T> implements IFixedQueue<T> {
-  private start!: number
-  /** @inheritdoc */
-  public readonly capacity: number
-  /** @inheritdoc */
-  public size!: number
-  /** @inheritdoc */
-  public nodeArray: FixedQueueNode<T>[]
-
-  /**
-   * Constructs a fixed queue.
-   * @param size - Fixed queue size. @defaultValue defaultQueueSize
-   * @returns FixedQueue.
-   */
-  constructor (size: number = defaultQueueSize) {
-    this.checkSize(size)
-    this.capacity = size
-    this.nodeArray = new Array<FixedQueueNode<T>>(this.capacity)
-    this.clear()
-  }
-
-  /** @inheritdoc */
-  public empty (): boolean {
-    return this.size === 0
-  }
-
-  /** @inheritdoc */
-  public full (): boolean {
-    return this.size === this.capacity
-  }
-
+export class FixedQueue<T>
+  extends AbstractFixedQueue<T>
+  implements IFixedQueue<T> {
   /** @inheritdoc */
   public enqueue (data: T, priority?: number): number {
     if (this.full()) {
@@ -64,65 +33,4 @@ export class FixedQueue<T> implements IFixedQueue<T> {
     }
     return this.nodeArray[index].data
   }
-
-  /** @inheritdoc */
-  public dequeue (): T | undefined {
-    if (this.empty()) {
-      return undefined
-    }
-    const index = this.start
-    --this.size
-    ++this.start
-    if (this.start === this.capacity) {
-      this.start = 0
-    }
-    return this.nodeArray[index].data
-  }
-
-  /** @inheritdoc */
-  public clear (): void {
-    this.start = 0
-    this.size = 0
-  }
-
-  /** @inheritdoc */
-  public [Symbol.iterator] (): Iterator<T> {
-    let index = this.start
-    let i = 0
-    return {
-      next: () => {
-        if (i >= this.size) {
-          return {
-            value: undefined,
-            done: true,
-          }
-        }
-        const value = this.nodeArray[index].data
-        ++index
-        ++i
-        if (index === this.capacity) {
-          index = 0
-        }
-        return {
-          value,
-          done: false,
-        }
-      },
-    }
-  }
-
-  /**
-   * Checks the fixed queue size.
-   * @param size - Queue size.
-   */
-  private checkSize (size: number): void {
-    if (!Number.isSafeInteger(size)) {
-      throw new TypeError(
-        `Invalid fixed queue size: '${size.toString()}' is not an integer`
-      )
-    }
-    if (size < 0) {
-      throw new RangeError(`Invalid fixed queue size: ${size.toString()} < 0`)
-    }
-  }
 }
index 41212c46856bfcfca1e531d28ffae882b6d80b55..57947ae8c84756483f5044be7914d23ebcedcc4f 100644 (file)
@@ -6,10 +6,10 @@ import { defaultQueueSize } from '../lib/utility-types.cjs'
 describe('Fixed priority queue test suite', () => {
   it('Verify constructor() behavior', () => {
     expect(() => new FixedPriorityQueue('')).toThrow(
-      new TypeError("Invalid fixed priority queue size: '' is not an integer")
+      new TypeError("Invalid fixed queue size: '' is not an integer")
     )
     expect(() => new FixedPriorityQueue(-1)).toThrow(
-      new RangeError('Invalid fixed priority queue size: -1 < 0')
+      new RangeError('Invalid fixed queue size: -1 < 0')
     )
     const fixedPriorityQueue = new FixedPriorityQueue()
     expect(fixedPriorityQueue.start).toBe(0)