All files / src/Queue Queue.ts

100% Statements 41/41
100% Branches 22/22
100% Functions 6/6
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134            5x                   425x 425x 425x 425x 425x               403x   403x   402x 40x     402x 3x     402x 399x     402x 362x     402x 303x     402x 402x                 5x                     18x                   329x   329x 297x     32x 11x     21x   21x 4x     21x   21x 17x     21x                   94x   94x 74x     20x               2x 2x      
/**
 * A node in a doubly-linked queue.
 * Represents a single item that can be added to or removed from a queue.
 * @template T - The base type of values in the queue
 * @template T1 - The specific type of this item's value (extends T)
 */
export class QueueItem<T = unknown, T1 extends T = T> {
  /**
   * Creates a new queue item.
   * @param value - The value stored in this item
   * @param deque - The queue this item belongs to
   * @param prev - The previous item in the queue
   * @param next - The next item in the queue
   * @param forced - Whether this is a forced/priority item
   */
  constructor (
    public value: T1,
    public deque?: Queue<T>,
    public prev?: QueueItem<T>,
    public next?: QueueItem<T>,
    public forced?: boolean,
  ) {}
 
  /**
   * Removes this item from its queue.
   * Updates the queue's linked list structure and decrements the size.
   */
  abort () {
    const deque = this.deque
 
    if (!deque) return
 
    if (this.next) {
      this.next.prev = this.prev
    }
 
    if (this.prev) {
      this.prev.next = this.next
    }
 
    if (deque.start === this) {
      deque.start = this.next
    }
 
    if (deque.end === this) {
      deque.end = this.prev
    }
 
    if (deque.forced === this) {
      deque.forced = this.prev
    }
 
    deque.size--
    this.deque = undefined
  }
}
 
/**
 * A doubly-linked queue with support for priority (forced) items.
 * Forced items are inserted at the front of the queue for immediate processing.
 * @template T - The type of values stored in the queue
 */
export class Queue<T> {
  /** The first item in the queue (next to be processed) */
  start?: QueueItem<T>
 
  /** The last forced (priority) item in the queue */
  forced?: QueueItem<T>
 
  /** The last item in the queue */
  end?: QueueItem<T>
 
  /** The number of items currently in the queue */
  size: number = 0
 
  /**
   * Adds a priority item to the queue.
   * Forced items are inserted after existing forced items but before regular items.
   * @template T1 - The specific type of the value (extends T)
   * @param value - The value to add
   * @returns The created queue item
   */
  force <T1 extends T>(value: T1): QueueItem<T, T1> {
    this.size++
 
    if (!this.start) {
      return this.forced = this.start = this.end = new QueueItem(value, this, undefined, undefined, true)
    }
 
    if (!this.forced) {
      return this.forced = this.start = this.start.prev = new QueueItem(value, this, undefined, this.start, true)
    }
 
    const newItem = new QueueItem(value, this, this.forced, this.forced.next, true)
 
    if (this.forced.next) {
      this.forced.next.prev = newItem
    }
 
    this.forced.next = newItem
 
    if (this.end === this.forced) {
      this.end = newItem
    }
 
    return this.forced = newItem
  }
 
  /**
   * Adds a regular item to the end of the queue.
   * @template T1 - The specific type of the value (extends T)
   * @param value - The value to add
   * @returns The created queue item
   */
  push <T1 extends T>(value: T1): QueueItem<T, T1> {
    this.size++
 
    if (!this.end) {
      return this.start = this.end = new QueueItem(value, this)
    }
 
    return this.end = this.end.next = new QueueItem(value, this, this.end)
  }
 
  /**
   * Removes all items from the queue.
   * Resets the queue to its initial empty state.
   */
  clear () {
    this.forced = this.start = this.end = undefined
    this.size = 0
  }
}