PriorityQueue.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. /**
  7. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  8. *
  9. * This source code is licensed under the MIT license found in the
  10. * LICENSE file in the root directory of this source tree.
  11. */
  12. /**
  13. * Priority queue that processes tasks in natural ordering (lower priority first)
  14. * according to the priority computed by the function passed in the constructor.
  15. *
  16. * FIFO ordering isn't guaranteed for tasks with the same priority.
  17. *
  18. * Worker specific tasks with the same priority as a non-worker specific task
  19. * are always processed first.
  20. */
  21. class PriorityQueue {
  22. _queue = [];
  23. _sharedQueue = new MinHeap();
  24. constructor(_computePriority) {
  25. this._computePriority = _computePriority;
  26. }
  27. enqueue(task, workerId) {
  28. if (workerId == null) {
  29. this._enqueue(task, this._sharedQueue);
  30. } else {
  31. const queue = this._getWorkerQueue(workerId);
  32. this._enqueue(task, queue);
  33. }
  34. }
  35. _enqueue(task, queue) {
  36. const item = {
  37. priority: this._computePriority(task.request[2], ...task.request[3]),
  38. task
  39. };
  40. queue.add(item);
  41. }
  42. dequeue(workerId) {
  43. const workerQueue = this._getWorkerQueue(workerId);
  44. const workerTop = workerQueue.peek();
  45. const sharedTop = this._sharedQueue.peek(); // use the task from the worker queue if there's no task in the shared queue
  46. // or if the priority of the worker queue is smaller or equal to the
  47. // priority of the top task in the shared queue. The tasks of the
  48. // worker specific queue are preferred because no other worker can pick this
  49. // specific task up.
  50. if (
  51. sharedTop == null ||
  52. (workerTop != null && workerTop.priority <= sharedTop.priority)
  53. ) {
  54. var _workerQueue$poll$tas, _workerQueue$poll;
  55. return (_workerQueue$poll$tas =
  56. (_workerQueue$poll = workerQueue.poll()) === null ||
  57. _workerQueue$poll === void 0
  58. ? void 0
  59. : _workerQueue$poll.task) !== null && _workerQueue$poll$tas !== void 0
  60. ? _workerQueue$poll$tas
  61. : null;
  62. }
  63. return this._sharedQueue.poll().task;
  64. }
  65. _getWorkerQueue(workerId) {
  66. let queue = this._queue[workerId];
  67. if (queue == null) {
  68. queue = this._queue[workerId] = new MinHeap();
  69. }
  70. return queue;
  71. }
  72. }
  73. exports.default = PriorityQueue;
  74. class MinHeap {
  75. _heap = [];
  76. peek() {
  77. var _this$_heap$;
  78. return (_this$_heap$ = this._heap[0]) !== null && _this$_heap$ !== void 0
  79. ? _this$_heap$
  80. : null;
  81. }
  82. add(item) {
  83. const nodes = this._heap;
  84. nodes.push(item);
  85. if (nodes.length === 1) {
  86. return;
  87. }
  88. let currentIndex = nodes.length - 1; // Bubble up the added node as long as the parent is bigger
  89. while (currentIndex > 0) {
  90. const parentIndex = Math.floor((currentIndex + 1) / 2) - 1;
  91. const parent = nodes[parentIndex];
  92. if (parent.priority <= item.priority) {
  93. break;
  94. }
  95. nodes[currentIndex] = parent;
  96. nodes[parentIndex] = item;
  97. currentIndex = parentIndex;
  98. }
  99. }
  100. poll() {
  101. const nodes = this._heap;
  102. const result = nodes[0];
  103. const lastElement = nodes.pop(); // heap was empty or removed the last element
  104. if (result == null || nodes.length === 0) {
  105. return result !== null && result !== void 0 ? result : null;
  106. }
  107. let index = 0;
  108. nodes[0] =
  109. lastElement !== null && lastElement !== void 0 ? lastElement : null;
  110. const element = nodes[0];
  111. while (true) {
  112. let swapIndex = null;
  113. const rightChildIndex = (index + 1) * 2;
  114. const leftChildIndex = rightChildIndex - 1;
  115. const rightChild = nodes[rightChildIndex];
  116. const leftChild = nodes[leftChildIndex]; // if the left child is smaller, swap with the left
  117. if (leftChild != null && leftChild.priority < element.priority) {
  118. swapIndex = leftChildIndex;
  119. } // If the right child is smaller or the right child is smaller than the left
  120. // then swap with the right child
  121. if (
  122. rightChild != null &&
  123. rightChild.priority < (swapIndex == null ? element : leftChild).priority
  124. ) {
  125. swapIndex = rightChildIndex;
  126. }
  127. if (swapIndex == null) {
  128. break;
  129. }
  130. nodes[index] = nodes[swapIndex];
  131. nodes[swapIndex] = element;
  132. index = swapIndex;
  133. }
  134. return result;
  135. }
  136. }