ArrayQueue.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /**
  7. * FIFO queue backed by arrays with a reversed dequeue buffer to avoid the cost
  8. * of repeated `Array#shift` operations.
  9. * @template T
  10. */
  11. class ArrayQueue {
  12. /**
  13. * Seeds the queue with an optional iterable of items in dequeue order.
  14. * @param {Iterable<T>=} items The initial elements.
  15. */
  16. constructor(items) {
  17. /**
  18. * @private
  19. * @type {T[]}
  20. */
  21. this._list = items ? [...items] : [];
  22. /**
  23. * @private
  24. * @type {T[]}
  25. */
  26. this._listReversed = [];
  27. }
  28. /**
  29. * Returns the current number of items waiting in either internal buffer.
  30. * @returns {number} The number of elements in this queue.
  31. */
  32. get length() {
  33. return this._list.length + this._listReversed.length;
  34. }
  35. /**
  36. * Removes all pending items from both internal buffers.
  37. */
  38. clear() {
  39. this._list.length = 0;
  40. this._listReversed.length = 0;
  41. }
  42. /**
  43. * Appends an item to the tail of the queue.
  44. * @param {T} item The element to add.
  45. * @returns {void}
  46. */
  47. enqueue(item) {
  48. this._list.push(item);
  49. }
  50. /**
  51. * Removes and returns the next item in FIFO order, switching to a reversed
  52. * buffer when that is cheaper than shifting from the front of the array.
  53. * @returns {T | undefined} The head of the queue of `undefined` if this queue is empty.
  54. */
  55. dequeue() {
  56. if (this._listReversed.length === 0) {
  57. if (this._list.length === 0) return;
  58. if (this._list.length === 1) return this._list.pop();
  59. if (this._list.length < 16) return this._list.shift();
  60. const temp = this._listReversed;
  61. this._listReversed = this._list;
  62. this._listReversed.reverse();
  63. this._list = temp;
  64. }
  65. return this._listReversed.pop();
  66. }
  67. /**
  68. * Removes the first matching item from whichever internal buffer currently
  69. * contains it.
  70. * @param {T} item the item
  71. * @returns {void}
  72. */
  73. delete(item) {
  74. const i = this._list.indexOf(item);
  75. if (i >= 0) {
  76. this._list.splice(i, 1);
  77. } else {
  78. const i = this._listReversed.indexOf(item);
  79. if (i >= 0) this._listReversed.splice(i, 1);
  80. }
  81. }
  82. [Symbol.iterator]() {
  83. return {
  84. next: () => {
  85. const item = this.dequeue();
  86. if (item) {
  87. return {
  88. done: false,
  89. value: item
  90. };
  91. }
  92. return {
  93. done: true,
  94. value: undefined
  95. };
  96. }
  97. };
  98. }
  99. }
  100. module.exports = ArrayQueue;