PriorityQueue.vala 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. void priority_queue_tests() {
  4. Test.add_func("/invercargill/priority_queue/basic_push_pop", () => {
  5. var pq = new PriorityQueue<int>((a, b) => a - b); // Min-heap (smaller values have higher priority)
  6. // Push items
  7. pq.push(5);
  8. pq.push(1);
  9. pq.push(3);
  10. pq.push(2);
  11. pq.push(4);
  12. // Pop in priority order (smallest first)
  13. assert_cmpint(1, CompareOperator.EQ, pq.pop());
  14. assert_cmpint(2, CompareOperator.EQ, pq.pop());
  15. assert_cmpint(3, CompareOperator.EQ, pq.pop());
  16. assert_cmpint(4, CompareOperator.EQ, pq.pop());
  17. assert_cmpint(5, CompareOperator.EQ, pq.pop());
  18. });
  19. Test.add_func("/invercargill/priority_queue/max_heap", () => {
  20. var pq = new PriorityQueue<int>((a, b) => b - a); // Max-heap (larger values have higher priority)
  21. // Push items
  22. pq.push(5);
  23. pq.push(1);
  24. pq.push(3);
  25. pq.push(2);
  26. pq.push(4);
  27. // Pop in priority order (largest first)
  28. assert_cmpint(5, CompareOperator.EQ, pq.pop());
  29. assert_cmpint(4, CompareOperator.EQ, pq.pop());
  30. assert_cmpint(3, CompareOperator.EQ, pq.pop());
  31. assert_cmpint(2, CompareOperator.EQ, pq.pop());
  32. assert_cmpint(1, CompareOperator.EQ, pq.pop());
  33. });
  34. Test.add_func("/invercargill/priority_queue/peek functionality", () => {
  35. var pq = new PriorityQueue<int>((a, b) => a - b); // Min-heap
  36. pq.push(5);
  37. pq.push(1);
  38. pq.push(3);
  39. // Peek should return highest priority item without removing
  40. var top = pq.peek();
  41. assert_cmpint(1, CompareOperator.EQ, top);
  42. // Pop should still return 1
  43. var popped = pq.pop();
  44. assert_cmpint(1, CompareOperator.EQ, popped);
  45. // Peek now should return 3 (next highest priority)
  46. var new_top = pq.peek();
  47. assert_cmpint(3, CompareOperator.EQ, new_top);
  48. });
  49. Test.add_func("/invercargill/priority_queue/empty_priority_queue_behavior", () => {
  50. // Test peek on empty priority queue
  51. var pq1 = new PriorityQueue<string>((a, b) => a.collate(b));
  52. try {
  53. pq1.peek();
  54. assert_not_reached();
  55. }
  56. catch (SequenceError e) {
  57. assert_cmpstr("No elements in priority queue", CompareOperator.EQ, e.message);
  58. }
  59. // Test pop on empty priority queue - need to unblock first
  60. var pq2 = new PriorityQueue<string>((a, b) => a.collate(b));
  61. pq2.unblock();
  62. try {
  63. pq2.pop();
  64. assert_not_reached();
  65. }
  66. catch (SequenceError e) {
  67. assert_cmpstr("No elements in unblocked priority queue to pop", CompareOperator.EQ, e.message);
  68. }
  69. });
  70. Test.add_func("/invercargill/priority_queue/push_all", () => {
  71. var pq = new PriorityQueue<int>((a, b) => a - b); // Min-heap
  72. var items = new Series<int>();
  73. items.add(5);
  74. items.add(1);
  75. items.add(3);
  76. // Push all items
  77. pq.push_all(items);
  78. // Should pop in priority order
  79. assert_cmpint(1, CompareOperator.EQ, pq.pop());
  80. assert_cmpint(3, CompareOperator.EQ, pq.pop());
  81. assert_cmpint(5, CompareOperator.EQ, pq.pop());
  82. });
  83. Test.add_func("/invercargill/priority_queue/enumerable_behavior", () => {
  84. var pq = new PriorityQueue<int>((a, b) => a - b); // Min-heap
  85. pq.push(5);
  86. pq.push(1);
  87. pq.push(3);
  88. pq.unblock();
  89. // Iteration should return items in priority order
  90. var tracker = pq.get_tracker();
  91. var items = new int[3];
  92. var index = 0;
  93. while (tracker.has_next()) {
  94. items[index++] = tracker.get_next();
  95. }
  96. assert_cmpint(1, CompareOperator.EQ, items[0]);
  97. assert_cmpint(3, CompareOperator.EQ, items[1]);
  98. assert_cmpint(5, CompareOperator.EQ, items[2]);
  99. });
  100. Test.add_func("/invercargill/priority_queue/blocking_behavior", () => {
  101. var pq = new PriorityQueue<string>((a, b) => a.collate(b));
  102. bool thread_started = false;
  103. bool thread_finished = false;
  104. // Start a thread that will wait for an item
  105. Thread<void*> thread = new Thread<void*>("test-thread", () => {
  106. thread_started = true;
  107. var item = pq.pop();
  108. assert_cmpstr("test_item", CompareOperator.EQ, item);
  109. thread_finished = true;
  110. return null;
  111. });
  112. // Wait for thread to start and block
  113. while (!thread_started) {
  114. Thread.usleep(1000); // 1ms
  115. }
  116. // Give additional time for thread to block on pop()
  117. Thread.usleep(50000); // 50ms
  118. // Push an item to unblock the thread
  119. pq.push("test_item");
  120. // Wait for thread to finish
  121. thread.join();
  122. assert_true(thread_finished);
  123. });
  124. Test.add_func("/invercargill/priority_queue/unblock_behavior", () => {
  125. var pq = new PriorityQueue<int>((a, b) => a - b);
  126. bool thread_started = false;
  127. bool exception_thrown = false;
  128. // Start a thread that will wait for an item
  129. Thread<void*> thread = new Thread<void*>("test-thread", () => {
  130. thread_started = true;
  131. try {
  132. var item = pq.pop(); // This should throw after unblock
  133. assert_not_reached();
  134. }
  135. catch (SequenceError e) {
  136. assert_cmpstr("No elements in unblocked priority queue to pop", CompareOperator.EQ, e.message);
  137. exception_thrown = true;
  138. }
  139. return null;
  140. });
  141. // Wait for thread to start and block
  142. while (!thread_started) {
  143. Thread.usleep(1000); // 1ms
  144. }
  145. // Give additional time for thread to block on pop()
  146. Thread.usleep(50000); // 50ms
  147. // Unblock the priority queue
  148. pq.unblock();
  149. // Wait for thread to finish
  150. thread.join();
  151. assert_true(exception_thrown);
  152. });
  153. Test.add_func("/invercargill/priority_queue/try_peek_and_try_pop", () => {
  154. var pq = new PriorityQueue<string>((a, b) => a.collate(b));
  155. // Try operations on empty priority queue
  156. string item;
  157. assert_false(pq.try_peek(out item));
  158. assert_null(item);
  159. string popped;
  160. pq.unblock();
  161. assert_false(pq.try_pop(out popped));
  162. assert_null(popped);
  163. // Add an item
  164. pq.push("test");
  165. // Try operations should now succeed
  166. assert_true(pq.try_peek(out item));
  167. assert_cmpstr("test", CompareOperator.EQ, item);
  168. assert_true(pq.try_pop(out popped));
  169. assert_cmpstr("test", CompareOperator.EQ, popped);
  170. // Should be empty again
  171. assert_false(pq.try_pop(out popped));
  172. assert_null(popped);
  173. });
  174. Test.add_func("/invercargill/priority_queue/duplicate_values", () => {
  175. var pq = new PriorityQueue<int>((a, b) => a - b); // Min-heap
  176. // Push items with duplicates
  177. pq.push(3);
  178. pq.push(1);
  179. pq.push(3);
  180. pq.push(2);
  181. pq.push(1);
  182. // Pop in priority order
  183. assert_cmpint(1, CompareOperator.EQ, pq.pop());
  184. assert_cmpint(1, CompareOperator.EQ, pq.pop());
  185. assert_cmpint(2, CompareOperator.EQ, pq.pop());
  186. assert_cmpint(3, CompareOperator.EQ, pq.pop());
  187. assert_cmpint(3, CompareOperator.EQ, pq.pop());
  188. });
  189. Test.add_func("/invercargill/priority_queue/peek_count", () => {
  190. var pq = new PriorityQueue<int>((a, b) => a - b); // Min-heap
  191. // Initially empty
  192. assert_cmpuint(0, CompareOperator.EQ, pq.peek_count());
  193. // Add items
  194. pq.push(3);
  195. assert_cmpuint(1, CompareOperator.EQ, pq.peek_count());
  196. pq.push(1);
  197. assert_cmpuint(2, CompareOperator.EQ, pq.peek_count());
  198. pq.push(2);
  199. assert_cmpuint(3, CompareOperator.EQ, pq.peek_count());
  200. // Remove items
  201. pq.pop();
  202. assert_cmpuint(2, CompareOperator.EQ, pq.peek_count());
  203. pq.pop();
  204. assert_cmpuint(1, CompareOperator.EQ, pq.peek_count());
  205. pq.pop();
  206. assert_cmpuint(0, CompareOperator.EQ, pq.peek_count());
  207. });
  208. Test.add_func("/invercargill/priority_queue/string_priority", () => {
  209. var pq = new PriorityQueue<string>((a, b) => a.collate(b)); // Alphabetical order
  210. // Push items
  211. pq.push("zebra");
  212. pq.push("apple");
  213. pq.push("banana");
  214. pq.push("cherry");
  215. // Pop in alphabetical order
  216. assert_cmpstr("apple", CompareOperator.EQ, pq.pop());
  217. assert_cmpstr("banana", CompareOperator.EQ, pq.pop());
  218. assert_cmpstr("cherry", CompareOperator.EQ, pq.pop());
  219. assert_cmpstr("zebra", CompareOperator.EQ, pq.pop());
  220. });
  221. }