authorgravatar for saurabh.m@proton.meSaurabh Mishra <saurabh.m@proton.me> 2026-02-26 21:09:52+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-26 21:09:52+01:00
log4e2cec265d37afd5ad320d0430060308de65326f
tree3ca62b6279e6af3756d83b6d8296f7d3d83e3330
parent0b6b65b387cdb145440a33922ab6c3fd10e6071f

Make `std.PriorityQueue` an unmanaged container (#31299)

## Summary of changes + Make adjustments to the `allocator` field and ensure the below tests pass: ```sh zig test lib/std/std.zig --zig-lib-dir lib zig build test-std -Dno-matrix --summary all ``` + Rename `add` to `push` and `remove` to `pop` in methods and tests + Incorporate the functionality of `pop` in `popOrNull`, then rename the `popOrNull` to `pop` and update tests + Use `.empty` to set default field values and rename the `init` method to `initContext` + Improve variable types in tests: min heap uses the less than context function and max heap uses greater than context function + Remove the `dump` method as its not being used anywhere + Document methods `clearRetainingCapacity`, `clearAndFree`, `update`, and `ensureTotalCapacityPrecise` Closes https://codeberg.org/ziglang/zig/issues/31298 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31299 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: Saurabh Mishra <saurabh.m@proton.me> Co-committed-by: Saurabh Mishra <saurabh.m@proton.me>

1 files changed, 279 insertions(+), 238 deletions(-)

lib/std/priority_queue.zig+279-238
......@@ -20,31 +20,36 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
2020
2121 items: []T,
2222 cap: usize,
23 allocator: Allocator,
2423 context: Context,
2524
26 /// Initialize and return a priority queue.
27 pub fn init(allocator: Allocator, context: Context) Self {
25 /// A priority queue containing no elements.
26 pub const empty: Self = .{
27 .items = &.{},
28 .cap = 0,
29 .context = undefined,
30 };
31
32 /// Initialize and return a priority queue with context.
33 pub fn initContext(context: Context) Self {
2834 return Self{
29 .items = &[_]T{},
35 .items = &.{},
3036 .cap = 0,
31 .allocator = allocator,
3237 .context = context,
3338 };
3439 }
3540
3641 /// Free memory used by the queue.
37 pub fn deinit(self: Self) void {
38 self.allocator.free(self.allocatedSlice());
42 pub fn deinit(self: *Self, allocator: Allocator) void {
43 allocator.free(self.allocatedSlice());
3944 }
4045
4146 /// Insert a new element, maintaining priority.
42 pub fn add(self: *Self, elem: T) !void {
43 try self.ensureUnusedCapacity(1);
44 addUnchecked(self, elem);
47 pub fn push(self: *Self, allocator: Allocator, elem: T) !void {
48 try self.ensureUnusedCapacity(allocator, 1);
49 pushUnchecked(self, elem);
4550 }
4651
47 fn addUnchecked(self: *Self, elem: T) void {
52 fn pushUnchecked(self: *Self, elem: T) void {
4853 self.items.len += 1;
4954 self.items[self.items.len - 1] = elem;
5055 siftUp(self, self.items.len - 1);
......@@ -64,10 +69,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
6469 }
6570
6671 /// Add each element in `items` to the queue.
67 pub fn addSlice(self: *Self, items: []const T) !void {
68 try self.ensureUnusedCapacity(items.len);
72 pub fn pushSlice(self: *Self, allocator: Allocator, items: []const T) !void {
73 try self.ensureUnusedCapacity(allocator, items.len);
6974 for (items) |e| {
70 self.addUnchecked(e);
75 self.pushUnchecked(e);
7176 }
7277 }
7378
......@@ -77,22 +82,16 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
7782 return if (self.items.len > 0) self.items[0] else null;
7883 }
7984
80 /// Pop the highest priority element from the queue. Returns
81 /// `null` if empty.
82 pub fn removeOrNull(self: *Self) ?T {
83 return if (self.items.len > 0) self.remove() else null;
84 }
85
86 /// Remove and return the highest priority element from the
87 /// queue.
88 pub fn remove(self: *Self) T {
89 return self.removeIndex(0);
85 /// Remove and return the highest priority element from the queue.
86 /// Returns `null` if empty.
87 pub fn pop(self: *Self) ?T {
88 return if (self.items.len > 0) self.popIndex(0) else null;
9089 }
9190
9291 /// Remove and return element at index. Indices are in the
9392 /// same order as iterator, which is not necessarily priority
9493 /// order.
95 pub fn removeIndex(self: *Self, index: usize) T {
94 pub fn popIndex(self: *Self, index: usize) T {
9695 assert(self.items.len > index);
9796 const last = self.items[self.items.len - 1];
9897 const item = self.items[index];
......@@ -158,11 +157,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
158157 /// PriorityQueue takes ownership of the passed in slice. The slice must have been
159158 /// allocated with `allocator`.
160159 /// Deinitialize with `deinit`.
161 pub fn fromOwnedSlice(allocator: Allocator, items: []T, context: Context) Self {
160 pub fn fromOwnedSlice(items: []T, context: Context) Self {
162161 var self = Self{
163162 .items = items,
164163 .cap = items.len,
165 .allocator = allocator,
166164 .context = context,
167165 };
168166
......@@ -175,39 +173,42 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
175173 }
176174
177175 /// Ensure that the queue can fit at least `new_capacity` items.
178 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void {
176 pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) !void {
179177 var better_capacity = self.cap;
180178 if (better_capacity >= new_capacity) return;
181179 while (true) {
182180 better_capacity += better_capacity / 2 + 8;
183181 if (better_capacity >= new_capacity) break;
184182 }
185 try self.ensureTotalCapacityPrecise(better_capacity);
183 try self.ensureTotalCapacityPrecise(allocator, better_capacity);
186184 }
187185
188 pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) !void {
186 /// If the current capacity is less than `new_capacity`, this function will
187 /// modify the array so that it can hold exactly `new_capacity` items.
188 /// Invalidates element pointers if additional memory is needed.
189 pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) !void {
189190 if (self.capacity() >= new_capacity) return;
190191
191192 const old_memory = self.allocatedSlice();
192 const new_memory = try self.allocator.realloc(old_memory, new_capacity);
193 const new_memory = try allocator.realloc(old_memory, new_capacity);
193194 self.items.ptr = new_memory.ptr;
194195 self.cap = new_memory.len;
195196 }
196197
197198 /// Ensure that the queue can fit at least `additional_count` **more** item.
198 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void {
199 return self.ensureTotalCapacity(self.items.len + additional_count);
199 pub fn ensureUnusedCapacity(self: *Self, allocator: Allocator, additional_count: usize) !void {
200 return self.ensureTotalCapacity(allocator, self.items.len + additional_count);
200201 }
201202
202203 /// Reduce allocated capacity to `new_capacity`.
203 pub fn shrinkAndFree(self: *Self, new_capacity: usize) void {
204 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_capacity: usize) void {
204205 assert(new_capacity <= self.cap);
205206
206207 // Cannot shrink to smaller than the current queue size without invalidating the heap property
207208 assert(new_capacity >= self.items.len);
208209
209210 const old_memory = self.allocatedSlice();
210 const new_memory = self.allocator.realloc(old_memory, new_capacity) catch |e| switch (e) {
211 const new_memory = allocator.realloc(old_memory, new_capacity) catch |e| switch (e) {
211212 error.OutOfMemory => { // no problem, capacity is still correct then.
212213 return;
213214 },
......@@ -217,16 +218,20 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
217218 self.cap = new_memory.len;
218219 }
219220
221 /// Remove all elements from the items slice.
220222 pub fn clearRetainingCapacity(self: *Self) void {
221223 self.items.len = 0;
222224 }
223225
224 pub fn clearAndFree(self: *Self) void {
225 self.allocator.free(self.allocatedSlice());
226 /// Invalidates all element pointers.
227 pub fn clearAndFree(self: *Self, allocator: Allocator) void {
228 allocator.free(self.allocatedSlice());
226229 self.items.len = 0;
227230 self.cap = 0;
228231 }
229232
233 /// Replace an element in the queue with a new element, maintaining priority.
234 /// If the element being updated doesn't exist, return `error.ElementNotFound`.
230235 pub fn update(self: *Self, elem: T, new_elem: T) !void {
231236 const update_index = blk: {
232237 var idx: usize = 0;
......@@ -270,22 +275,6 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
270275 .count = 0,
271276 };
272277 }
273
274 fn dump(self: *Self) void {
275 const print = std.debug.print;
276 print("{{ ", .{});
277 print("items: ", .{});
278 for (self.items) |e| {
279 print("{}, ", .{e});
280 }
281 print("array: ", .{});
282 for (self.items) |e| {
283 print("{}, ", .{e});
284 }
285 print("len: {} ", .{self.items.len});
286 print("capacity: {}", .{self.cap});
287 print(" }}\n", .{});
288 }
289278 };
290279}
291280
......@@ -298,181 +287,213 @@ fn greaterThan(context: void, a: u32, b: u32) Order {
298287 return lessThan(context, a, b).invert();
299288}
300289
301const PQlt = PriorityQueue(u32, void, lessThan);
302const PQgt = PriorityQueue(u32, void, greaterThan);
290const MinHeap = PriorityQueue(u32, void, lessThan);
291const MaxHeap = PriorityQueue(u32, void, greaterThan);
303292
304293test "add and remove min heap" {
305 var queue = PQlt.init(testing.allocator, {});
306 defer queue.deinit();
307
308 try queue.add(54);
309 try queue.add(12);
310 try queue.add(7);
311 try queue.add(23);
312 try queue.add(25);
313 try queue.add(13);
314 try expectEqual(@as(u32, 7), queue.remove());
315 try expectEqual(@as(u32, 12), queue.remove());
316 try expectEqual(@as(u32, 13), queue.remove());
317 try expectEqual(@as(u32, 23), queue.remove());
318 try expectEqual(@as(u32, 25), queue.remove());
319 try expectEqual(@as(u32, 54), queue.remove());
294 const gpa = testing.allocator;
295
296 var queue: MinHeap = .empty;
297 defer queue.deinit(gpa);
298
299 try queue.push(gpa, 54);
300 try queue.push(gpa, 12);
301 try queue.push(gpa, 7);
302 try queue.push(gpa, 23);
303 try queue.push(gpa, 25);
304 try queue.push(gpa, 13);
305 try expectEqual(@as(u32, 7), queue.pop());
306 try expectEqual(@as(u32, 12), queue.pop());
307 try expectEqual(@as(u32, 13), queue.pop());
308 try expectEqual(@as(u32, 23), queue.pop());
309 try expectEqual(@as(u32, 25), queue.pop());
310 try expectEqual(@as(u32, 54), queue.pop());
320311}
321312
322313test "add and remove same min heap" {
323 var queue = PQlt.init(testing.allocator, {});
324 defer queue.deinit();
325
326 try queue.add(1);
327 try queue.add(1);
328 try queue.add(2);
329 try queue.add(2);
330 try queue.add(1);
331 try queue.add(1);
332 try expectEqual(@as(u32, 1), queue.remove());
333 try expectEqual(@as(u32, 1), queue.remove());
334 try expectEqual(@as(u32, 1), queue.remove());
335 try expectEqual(@as(u32, 1), queue.remove());
336 try expectEqual(@as(u32, 2), queue.remove());
337 try expectEqual(@as(u32, 2), queue.remove());
314 const gpa = testing.allocator;
315
316 var queue: MinHeap = .empty;
317 defer queue.deinit(gpa);
318
319 try queue.push(gpa, 1);
320 try queue.push(gpa, 1);
321 try queue.push(gpa, 2);
322 try queue.push(gpa, 2);
323 try queue.push(gpa, 1);
324 try queue.push(gpa, 1);
325 try expectEqual(@as(u32, 1), queue.pop());
326 try expectEqual(@as(u32, 1), queue.pop());
327 try expectEqual(@as(u32, 1), queue.pop());
328 try expectEqual(@as(u32, 1), queue.pop());
329 try expectEqual(@as(u32, 2), queue.pop());
330 try expectEqual(@as(u32, 2), queue.pop());
338331}
339332
340333test "removeOrNull on empty" {
341 var queue = PQlt.init(testing.allocator, {});
342 defer queue.deinit();
334 const gpa = testing.allocator;
335
336 var queue: MinHeap = .empty;
337 defer queue.deinit(gpa);
343338
344 try expect(queue.removeOrNull() == null);
339 try expect(queue.pop() == null);
345340}
346341
347342test "edge case 3 elements" {
348 var queue = PQlt.init(testing.allocator, {});
349 defer queue.deinit();
350
351 try queue.add(9);
352 try queue.add(3);
353 try queue.add(2);
354 try expectEqual(@as(u32, 2), queue.remove());
355 try expectEqual(@as(u32, 3), queue.remove());
356 try expectEqual(@as(u32, 9), queue.remove());
343 const gpa = testing.allocator;
344
345 var queue: MinHeap = .empty;
346 defer queue.deinit(gpa);
347
348 try queue.push(gpa, 9);
349 try queue.push(gpa, 3);
350 try queue.push(gpa, 2);
351 try expectEqual(@as(u32, 2), queue.pop());
352 try expectEqual(@as(u32, 3), queue.pop());
353 try expectEqual(@as(u32, 9), queue.pop());
357354}
358355
359356test "peek" {
360 var queue = PQlt.init(testing.allocator, {});
361 defer queue.deinit();
357 const gpa = testing.allocator;
358
359 var queue: MinHeap = .empty;
360 defer queue.deinit(gpa);
362361
363362 try expect(queue.peek() == null);
364 try queue.add(9);
365 try queue.add(3);
366 try queue.add(2);
363 try queue.push(gpa, 9);
364 try queue.push(gpa, 3);
365 try queue.push(gpa, 2);
367366 try expectEqual(@as(u32, 2), queue.peek().?);
368367 try expectEqual(@as(u32, 2), queue.peek().?);
369368}
370369
371370test "sift up with odd indices" {
372 var queue = PQlt.init(testing.allocator, {});
373 defer queue.deinit();
371 const gpa = testing.allocator;
372
373 var queue: MinHeap = .empty;
374 defer queue.deinit(gpa);
375
374376 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
375377 for (items) |e| {
376 try queue.add(e);
378 try queue.push(gpa, e);
377379 }
378380
379381 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
380382 for (sorted_items) |e| {
381 try expectEqual(e, queue.remove());
383 try expectEqual(e, queue.pop());
382384 }
383385}
384386
385387test "addSlice" {
386 var queue = PQlt.init(testing.allocator, {});
387 defer queue.deinit();
388 const gpa = testing.allocator;
389
390 var queue: MinHeap = .empty;
391 defer queue.deinit(gpa);
392
388393 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
389 try queue.addSlice(items[0..]);
394 try queue.pushSlice(gpa, items[0..]);
390395
391396 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
392397 for (sorted_items) |e| {
393 try expectEqual(e, queue.remove());
398 try expectEqual(e, queue.pop());
394399 }
395400}
396401
397402test "fromOwnedSlice trivial case 0" {
403 const gpa = testing.allocator;
404
398405 const items = [0]u32{};
399 const queue_items = try testing.allocator.dupe(u32, &items);
400 var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {});
401 defer queue.deinit();
406 const queue_items = try gpa.dupe(u32, &items);
407
408 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
409 defer queue.deinit(gpa);
410
402411 try expectEqual(@as(usize, 0), queue.count());
403 try expect(queue.removeOrNull() == null);
412 try expect(queue.pop() == null);
404413}
405414
406415test "fromOwnedSlice trivial case 1" {
416 const gpa = testing.allocator;
417
407418 const items = [1]u32{1};
408 const queue_items = try testing.allocator.dupe(u32, &items);
409 var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {});
410 defer queue.deinit();
419 const queue_items = try gpa.dupe(u32, &items);
420
421 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
422 defer queue.deinit(gpa);
411423
412424 try expectEqual(@as(usize, 1), queue.count());
413 try expectEqual(items[0], queue.remove());
414 try expect(queue.removeOrNull() == null);
425 try expectEqual(items[0], queue.pop());
426 try expect(queue.pop() == null);
415427}
416428
417429test "fromOwnedSlice" {
430 const gpa = testing.allocator;
431
418432 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
419 const heap_items = try testing.allocator.dupe(u32, items[0..]);
420 var queue = PQlt.fromOwnedSlice(testing.allocator, heap_items[0..], {});
421 defer queue.deinit();
433 const heap_items = try gpa.dupe(u32, items[0..]);
434
435 var queue: MinHeap = .fromOwnedSlice(heap_items[0..], {});
436 defer queue.deinit(gpa);
422437
423438 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
424439 for (sorted_items) |e| {
425 try expectEqual(e, queue.remove());
440 try expectEqual(e, queue.pop());
426441 }
427442}
428443
429444test "add and remove max heap" {
430 var queue = PQgt.init(testing.allocator, {});
431 defer queue.deinit();
432
433 try queue.add(54);
434 try queue.add(12);
435 try queue.add(7);
436 try queue.add(23);
437 try queue.add(25);
438 try queue.add(13);
439 try expectEqual(@as(u32, 54), queue.remove());
440 try expectEqual(@as(u32, 25), queue.remove());
441 try expectEqual(@as(u32, 23), queue.remove());
442 try expectEqual(@as(u32, 13), queue.remove());
443 try expectEqual(@as(u32, 12), queue.remove());
444 try expectEqual(@as(u32, 7), queue.remove());
445 const gpa = testing.allocator;
446
447 var queue: MaxHeap = .empty;
448 defer queue.deinit(gpa);
449
450 try queue.push(gpa, 54);
451 try queue.push(gpa, 12);
452 try queue.push(gpa, 7);
453 try queue.push(gpa, 23);
454 try queue.push(gpa, 25);
455 try queue.push(gpa, 13);
456 try expectEqual(@as(u32, 54), queue.pop());
457 try expectEqual(@as(u32, 25), queue.pop());
458 try expectEqual(@as(u32, 23), queue.pop());
459 try expectEqual(@as(u32, 13), queue.pop());
460 try expectEqual(@as(u32, 12), queue.pop());
461 try expectEqual(@as(u32, 7), queue.pop());
445462}
446463
447464test "add and remove same max heap" {
448 var queue = PQgt.init(testing.allocator, {});
449 defer queue.deinit();
450
451 try queue.add(1);
452 try queue.add(1);
453 try queue.add(2);
454 try queue.add(2);
455 try queue.add(1);
456 try queue.add(1);
457 try expectEqual(@as(u32, 2), queue.remove());
458 try expectEqual(@as(u32, 2), queue.remove());
459 try expectEqual(@as(u32, 1), queue.remove());
460 try expectEqual(@as(u32, 1), queue.remove());
461 try expectEqual(@as(u32, 1), queue.remove());
462 try expectEqual(@as(u32, 1), queue.remove());
465 const gpa = testing.allocator;
466
467 var queue: MaxHeap = .empty;
468 defer queue.deinit(gpa);
469
470 try queue.push(gpa, 1);
471 try queue.push(gpa, 1);
472 try queue.push(gpa, 2);
473 try queue.push(gpa, 2);
474 try queue.push(gpa, 1);
475 try queue.push(gpa, 1);
476 try expectEqual(@as(u32, 2), queue.pop());
477 try expectEqual(@as(u32, 2), queue.pop());
478 try expectEqual(@as(u32, 1), queue.pop());
479 try expectEqual(@as(u32, 1), queue.pop());
480 try expectEqual(@as(u32, 1), queue.pop());
481 try expectEqual(@as(u32, 1), queue.pop());
463482}
464483
465484test "iterator" {
466 var queue = PQlt.init(testing.allocator, {});
485 const gpa = testing.allocator;
486
487 var queue: MinHeap = .empty;
467488 var map = std.AutoHashMap(u32, void).init(testing.allocator);
468489 defer {
469 queue.deinit();
490 queue.deinit(gpa);
470491 map.deinit();
471492 }
472493
473494 const items = [_]u32{ 54, 12, 7, 23, 25, 13 };
474495 for (items) |e| {
475 _ = try queue.add(e);
496 _ = try queue.push(gpa, e);
476497 try map.put(e, {});
477498 }
478499
......@@ -485,12 +506,14 @@ test "iterator" {
485506}
486507
487508test "remove at index" {
488 var queue = PQlt.init(testing.allocator, {});
489 defer queue.deinit();
509 const gpa = testing.allocator;
510
511 var queue: MinHeap = .empty;
512 defer queue.deinit(gpa);
490513
491514 const items = [_]u32{ 2, 1, 8, 9, 3, 4, 5 };
492515 for (items) |e| {
493 _ = try queue.add(e);
516 _ = try queue.push(gpa, e);
494517 }
495518
496519 var it = queue.iterator();
......@@ -501,18 +524,20 @@ test "remove at index" {
501524 idx += 1;
502525 } else unreachable;
503526 const sorted_items = [_]u32{ 1, 3, 4, 5, 8, 9 };
504 try expectEqual(queue.removeIndex(two_idx), 2);
527 try expectEqual(queue.popIndex(two_idx), 2);
505528
506529 var i: usize = 0;
507 while (queue.removeOrNull()) |n| : (i += 1) {
530 while (queue.pop()) |n| : (i += 1) {
508531 try expectEqual(n, sorted_items[i]);
509532 }
510 try expectEqual(queue.removeOrNull(), null);
533 try expectEqual(queue.pop(), null);
511534}
512535
513536test "iterator while empty" {
514 var queue = PQlt.init(testing.allocator, {});
515 defer queue.deinit();
537 const gpa = testing.allocator;
538
539 var queue: MinHeap = .empty;
540 defer queue.deinit(gpa);
516541
517542 var it = queue.iterator();
518543
......@@ -520,110 +545,124 @@ test "iterator while empty" {
520545}
521546
522547test "shrinkAndFree" {
523 var queue = PQlt.init(testing.allocator, {});
524 defer queue.deinit();
548 const gpa = testing.allocator;
549
550 var queue: MinHeap = .empty;
551 defer queue.deinit(gpa);
525552
526 try queue.ensureTotalCapacity(4);
553 try queue.ensureTotalCapacity(gpa, 4);
527554 try expect(queue.capacity() >= 4);
528555
529 try queue.add(1);
530 try queue.add(2);
531 try queue.add(3);
556 try queue.push(gpa, 1);
557 try queue.push(gpa, 2);
558 try queue.push(gpa, 3);
532559 try expect(queue.capacity() >= 4);
533560 try expectEqual(@as(usize, 3), queue.count());
534561
535 queue.shrinkAndFree(3);
562 queue.shrinkAndFree(gpa, 3);
536563 try expectEqual(@as(usize, 3), queue.capacity());
537564 try expectEqual(@as(usize, 3), queue.count());
538565
539 try expectEqual(@as(u32, 1), queue.remove());
540 try expectEqual(@as(u32, 2), queue.remove());
541 try expectEqual(@as(u32, 3), queue.remove());
542 try expect(queue.removeOrNull() == null);
566 try expectEqual(@as(u32, 1), queue.pop());
567 try expectEqual(@as(u32, 2), queue.pop());
568 try expectEqual(@as(u32, 3), queue.pop());
569 try expect(queue.pop() == null);
543570}
544571
545572test "update min heap" {
546 var queue = PQlt.init(testing.allocator, {});
547 defer queue.deinit();
573 const gpa = testing.allocator;
574
575 var queue: MinHeap = .empty;
576 defer queue.deinit(gpa);
548577
549 try queue.add(55);
550 try queue.add(44);
551 try queue.add(11);
578 try queue.push(gpa, 55);
579 try queue.push(gpa, 44);
580 try queue.push(gpa, 11);
552581 try queue.update(55, 5);
553582 try queue.update(44, 4);
554583 try queue.update(11, 1);
555 try expectEqual(@as(u32, 1), queue.remove());
556 try expectEqual(@as(u32, 4), queue.remove());
557 try expectEqual(@as(u32, 5), queue.remove());
584 try expectEqual(@as(u32, 1), queue.pop());
585 try expectEqual(@as(u32, 4), queue.pop());
586 try expectEqual(@as(u32, 5), queue.pop());
558587}
559588
560589test "update same min heap" {
561 var queue = PQlt.init(testing.allocator, {});
562 defer queue.deinit();
590 const gpa = testing.allocator;
563591
564 try queue.add(1);
565 try queue.add(1);
566 try queue.add(2);
567 try queue.add(2);
592 var queue: MinHeap = .empty;
593 defer queue.deinit(gpa);
594
595 try queue.push(gpa, 1);
596 try queue.push(gpa, 1);
597 try queue.push(gpa, 2);
598 try queue.push(gpa, 2);
568599 try queue.update(1, 5);
569600 try queue.update(2, 4);
570 try expectEqual(@as(u32, 1), queue.remove());
571 try expectEqual(@as(u32, 2), queue.remove());
572 try expectEqual(@as(u32, 4), queue.remove());
573 try expectEqual(@as(u32, 5), queue.remove());
601 try expectEqual(@as(u32, 1), queue.pop());
602 try expectEqual(@as(u32, 2), queue.pop());
603 try expectEqual(@as(u32, 4), queue.pop());
604 try expectEqual(@as(u32, 5), queue.pop());
574605}
575606
576607test "update max heap" {
577 var queue = PQgt.init(testing.allocator, {});
578 defer queue.deinit();
608 const gpa = testing.allocator;
609
610 var queue: MaxHeap = .empty;
611 defer queue.deinit(gpa);
579612
580 try queue.add(55);
581 try queue.add(44);
582 try queue.add(11);
613 try queue.push(gpa, 55);
614 try queue.push(gpa, 44);
615 try queue.push(gpa, 11);
583616 try queue.update(55, 5);
584617 try queue.update(44, 1);
585618 try queue.update(11, 4);
586 try expectEqual(@as(u32, 5), queue.remove());
587 try expectEqual(@as(u32, 4), queue.remove());
588 try expectEqual(@as(u32, 1), queue.remove());
619 try expectEqual(@as(u32, 5), queue.pop());
620 try expectEqual(@as(u32, 4), queue.pop());
621 try expectEqual(@as(u32, 1), queue.pop());
589622}
590623
591624test "update same max heap" {
592 var queue = PQgt.init(testing.allocator, {});
593 defer queue.deinit();
625 const gpa = testing.allocator;
594626
595 try queue.add(1);
596 try queue.add(1);
597 try queue.add(2);
598 try queue.add(2);
627 var queue: MaxHeap = .empty;
628 defer queue.deinit(gpa);
629
630 try queue.push(gpa, 1);
631 try queue.push(gpa, 1);
632 try queue.push(gpa, 2);
633 try queue.push(gpa, 2);
599634 try queue.update(1, 5);
600635 try queue.update(2, 4);
601 try expectEqual(@as(u32, 5), queue.remove());
602 try expectEqual(@as(u32, 4), queue.remove());
603 try expectEqual(@as(u32, 2), queue.remove());
604 try expectEqual(@as(u32, 1), queue.remove());
636 try expectEqual(@as(u32, 5), queue.pop());
637 try expectEqual(@as(u32, 4), queue.pop());
638 try expectEqual(@as(u32, 2), queue.pop());
639 try expectEqual(@as(u32, 1), queue.pop());
605640}
606641
607642test "update after remove" {
608 var queue = PQlt.init(testing.allocator, {});
609 defer queue.deinit();
643 const gpa = testing.allocator;
644
645 var queue: MinHeap = .empty;
646 defer queue.deinit(gpa);
610647
611 try queue.add(1);
612 try expectEqual(@as(u32, 1), queue.remove());
648 try queue.push(gpa, 1);
649 try expectEqual(@as(u32, 1), queue.pop());
613650 try expectError(error.ElementNotFound, queue.update(1, 1));
614651}
615652
616653test "siftUp in remove" {
617 var queue = PQlt.init(testing.allocator, {});
618 defer queue.deinit();
654 const gpa = testing.allocator;
619655
620 try queue.addSlice(&.{ 0, 1, 100, 2, 3, 101, 102, 4, 5, 6, 7, 103, 104, 105, 106, 8 });
656 var queue: MinHeap = .empty;
657 defer queue.deinit(gpa);
621658
622 _ = queue.removeIndex(std.mem.findScalar(u32, queue.items[0..queue.count()], 102).?);
659 try queue.pushSlice(gpa, &.{ 0, 1, 100, 2, 3, 101, 102, 4, 5, 6, 7, 103, 104, 105, 106, 8 });
660
661 _ = queue.popIndex(std.mem.findScalar(u32, queue.items[0..queue.count()], 102).?);
623662
624663 const sorted_items = [_]u32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 103, 104, 105, 106 };
625664 for (sorted_items) |e| {
626 try expectEqual(e, queue.remove());
665 try expectEqual(e, queue.pop());
627666 }
628667}
629668
......@@ -631,26 +670,28 @@ fn contextLessThan(context: []const u32, a: usize, b: usize) Order {
631670 return std.math.order(context[a], context[b]);
632671}
633672
634const CPQlt = PriorityQueue(usize, []const u32, contextLessThan);
673const MinHeapWithContext = PriorityQueue(usize, []const u32, contextLessThan);
635674
636675test "add and remove min heap with context comparator" {
676 const gpa = testing.allocator;
677
637678 const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };
638679
639 var queue = CPQlt.init(testing.allocator, context[0..]);
640 defer queue.deinit();
641
642 try queue.add(0);
643 try queue.add(1);
644 try queue.add(2);
645 try queue.add(3);
646 try queue.add(4);
647 try queue.add(5);
648 try queue.add(6);
649 try expectEqual(@as(usize, 6), queue.remove());
650 try expectEqual(@as(usize, 4), queue.remove());
651 try expectEqual(@as(usize, 3), queue.remove());
652 try expectEqual(@as(usize, 1), queue.remove());
653 try expectEqual(@as(usize, 2), queue.remove());
654 try expectEqual(@as(usize, 0), queue.remove());
655 try expectEqual(@as(usize, 5), queue.remove());
680 var queue: MinHeapWithContext = .initContext(context[0..]);
681 defer queue.deinit(gpa);
682
683 try queue.push(gpa, 0);
684 try queue.push(gpa, 1);
685 try queue.push(gpa, 2);
686 try queue.push(gpa, 3);
687 try queue.push(gpa, 4);
688 try queue.push(gpa, 5);
689 try queue.push(gpa, 6);
690 try expectEqual(@as(usize, 6), queue.pop());
691 try expectEqual(@as(usize, 4), queue.pop());
692 try expectEqual(@as(usize, 3), queue.pop());
693 try expectEqual(@as(usize, 1), queue.pop());
694 try expectEqual(@as(usize, 2), queue.pop());
695 try expectEqual(@as(usize, 0), queue.pop());
696 try expectEqual(@as(usize, 5), queue.pop());
656697}