From 4e2cec265d37afd5ad320d0430060308de65326f Mon Sep 17 00:00:00 2001 From: Saurabh Mishra Date: Thu, 26 Feb 2026 21:09:52 +0100 Subject: [PATCH] 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 Co-authored-by: Saurabh Mishra Co-committed-by: Saurabh Mishra --- lib/std/priority_queue.zig | 505 ++++++++++++++++++++----------------- 1 file changed, 273 insertions(+), 232 deletions(-) diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index 3eae43f3c6..cb70d6c123 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -20,31 +20,36 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF items: []T, cap: usize, - allocator: Allocator, context: Context, - /// Initialize and return a priority queue. - pub fn init(allocator: Allocator, context: Context) Self { + /// A priority queue containing no elements. + pub const empty: Self = .{ + .items = &.{}, + .cap = 0, + .context = undefined, + }; + + /// Initialize and return a priority queue with context. + pub fn initContext(context: Context) Self { return Self{ - .items = &[_]T{}, + .items = &.{}, .cap = 0, - .allocator = allocator, .context = context, }; } /// Free memory used by the queue. - pub fn deinit(self: Self) void { - self.allocator.free(self.allocatedSlice()); + pub fn deinit(self: *Self, allocator: Allocator) void { + allocator.free(self.allocatedSlice()); } /// Insert a new element, maintaining priority. - pub fn add(self: *Self, elem: T) !void { - try self.ensureUnusedCapacity(1); - addUnchecked(self, elem); + pub fn push(self: *Self, allocator: Allocator, elem: T) !void { + try self.ensureUnusedCapacity(allocator, 1); + pushUnchecked(self, elem); } - fn addUnchecked(self: *Self, elem: T) void { + fn pushUnchecked(self: *Self, elem: T) void { self.items.len += 1; self.items[self.items.len - 1] = elem; siftUp(self, self.items.len - 1); @@ -64,10 +69,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF } /// Add each element in `items` to the queue. - pub fn addSlice(self: *Self, items: []const T) !void { - try self.ensureUnusedCapacity(items.len); + pub fn pushSlice(self: *Self, allocator: Allocator, items: []const T) !void { + try self.ensureUnusedCapacity(allocator, items.len); for (items) |e| { - self.addUnchecked(e); + self.pushUnchecked(e); } } @@ -77,22 +82,16 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF return if (self.items.len > 0) self.items[0] else null; } - /// Pop the highest priority element from the queue. Returns - /// `null` if empty. - pub fn removeOrNull(self: *Self) ?T { - return if (self.items.len > 0) self.remove() else null; - } - - /// Remove and return the highest priority element from the - /// queue. - pub fn remove(self: *Self) T { - return self.removeIndex(0); + /// Remove and return the highest priority element from the queue. + /// Returns `null` if empty. + pub fn pop(self: *Self) ?T { + return if (self.items.len > 0) self.popIndex(0) else null; } /// Remove and return element at index. Indices are in the /// same order as iterator, which is not necessarily priority /// order. - pub fn removeIndex(self: *Self, index: usize) T { + pub fn popIndex(self: *Self, index: usize) T { assert(self.items.len > index); const last = self.items[self.items.len - 1]; const item = self.items[index]; @@ -158,11 +157,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF /// PriorityQueue takes ownership of the passed in slice. The slice must have been /// allocated with `allocator`. /// Deinitialize with `deinit`. - pub fn fromOwnedSlice(allocator: Allocator, items: []T, context: Context) Self { + pub fn fromOwnedSlice(items: []T, context: Context) Self { var self = Self{ .items = items, .cap = items.len, - .allocator = allocator, .context = context, }; @@ -175,39 +173,42 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF } /// Ensure that the queue can fit at least `new_capacity` items. - pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { + pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) !void { var better_capacity = self.cap; if (better_capacity >= new_capacity) return; while (true) { better_capacity += better_capacity / 2 + 8; if (better_capacity >= new_capacity) break; } - try self.ensureTotalCapacityPrecise(better_capacity); + try self.ensureTotalCapacityPrecise(allocator, better_capacity); } - pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) !void { + /// If the current capacity is less than `new_capacity`, this function will + /// modify the array so that it can hold exactly `new_capacity` items. + /// Invalidates element pointers if additional memory is needed. + pub fn ensureTotalCapacityPrecise(self: *Self, allocator: Allocator, new_capacity: usize) !void { if (self.capacity() >= new_capacity) return; const old_memory = self.allocatedSlice(); - const new_memory = try self.allocator.realloc(old_memory, new_capacity); + const new_memory = try allocator.realloc(old_memory, new_capacity); self.items.ptr = new_memory.ptr; self.cap = new_memory.len; } /// Ensure that the queue can fit at least `additional_count` **more** item. - pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void { - return self.ensureTotalCapacity(self.items.len + additional_count); + pub fn ensureUnusedCapacity(self: *Self, allocator: Allocator, additional_count: usize) !void { + return self.ensureTotalCapacity(allocator, self.items.len + additional_count); } /// Reduce allocated capacity to `new_capacity`. - pub fn shrinkAndFree(self: *Self, new_capacity: usize) void { + pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_capacity: usize) void { assert(new_capacity <= self.cap); // Cannot shrink to smaller than the current queue size without invalidating the heap property assert(new_capacity >= self.items.len); const old_memory = self.allocatedSlice(); - const new_memory = self.allocator.realloc(old_memory, new_capacity) catch |e| switch (e) { + const new_memory = allocator.realloc(old_memory, new_capacity) catch |e| switch (e) { error.OutOfMemory => { // no problem, capacity is still correct then. return; }, @@ -217,16 +218,20 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF self.cap = new_memory.len; } + /// Remove all elements from the items slice. pub fn clearRetainingCapacity(self: *Self) void { self.items.len = 0; } - pub fn clearAndFree(self: *Self) void { - self.allocator.free(self.allocatedSlice()); + /// Invalidates all element pointers. + pub fn clearAndFree(self: *Self, allocator: Allocator) void { + allocator.free(self.allocatedSlice()); self.items.len = 0; self.cap = 0; } + /// Replace an element in the queue with a new element, maintaining priority. + /// If the element being updated doesn't exist, return `error.ElementNotFound`. pub fn update(self: *Self, elem: T, new_elem: T) !void { const update_index = blk: { var idx: usize = 0; @@ -270,22 +275,6 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF .count = 0, }; } - - fn dump(self: *Self) void { - const print = std.debug.print; - print("{{ ", .{}); - print("items: ", .{}); - for (self.items) |e| { - print("{}, ", .{e}); - } - print("array: ", .{}); - for (self.items) |e| { - print("{}, ", .{e}); - } - print("len: {} ", .{self.items.len}); - print("capacity: {}", .{self.cap}); - print(" }}\n", .{}); - } }; } @@ -298,181 +287,213 @@ fn greaterThan(context: void, a: u32, b: u32) Order { return lessThan(context, a, b).invert(); } -const PQlt = PriorityQueue(u32, void, lessThan); -const PQgt = PriorityQueue(u32, void, greaterThan); +const MinHeap = PriorityQueue(u32, void, lessThan); +const MaxHeap = PriorityQueue(u32, void, greaterThan); test "add and remove min heap" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(54); - try queue.add(12); - try queue.add(7); - try queue.add(23); - try queue.add(25); - try queue.add(13); - try expectEqual(@as(u32, 7), queue.remove()); - try expectEqual(@as(u32, 12), queue.remove()); - try expectEqual(@as(u32, 13), queue.remove()); - try expectEqual(@as(u32, 23), queue.remove()); - try expectEqual(@as(u32, 25), queue.remove()); - try expectEqual(@as(u32, 54), queue.remove()); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 54); + try queue.push(gpa, 12); + try queue.push(gpa, 7); + try queue.push(gpa, 23); + try queue.push(gpa, 25); + try queue.push(gpa, 13); + try expectEqual(@as(u32, 7), queue.pop()); + try expectEqual(@as(u32, 12), queue.pop()); + try expectEqual(@as(u32, 13), queue.pop()); + try expectEqual(@as(u32, 23), queue.pop()); + try expectEqual(@as(u32, 25), queue.pop()); + try expectEqual(@as(u32, 54), queue.pop()); } test "add and remove same min heap" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(1); - try queue.add(1); - try queue.add(2); - try queue.add(2); - try queue.add(1); - try queue.add(1); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 2), queue.remove()); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 1); + try queue.push(gpa, 1); + try queue.push(gpa, 2); + try queue.push(gpa, 2); + try queue.push(gpa, 1); + try queue.push(gpa, 1); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 2), queue.pop()); } test "removeOrNull on empty" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try expect(queue.removeOrNull() == null); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try expect(queue.pop() == null); } test "edge case 3 elements" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(9); - try queue.add(3); - try queue.add(2); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 3), queue.remove()); - try expectEqual(@as(u32, 9), queue.remove()); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 9); + try queue.push(gpa, 3); + try queue.push(gpa, 2); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 3), queue.pop()); + try expectEqual(@as(u32, 9), queue.pop()); } test "peek" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; + + var queue: MinHeap = .empty; + defer queue.deinit(gpa); try expect(queue.peek() == null); - try queue.add(9); - try queue.add(3); - try queue.add(2); + try queue.push(gpa, 9); + try queue.push(gpa, 3); + try queue.push(gpa, 2); try expectEqual(@as(u32, 2), queue.peek().?); try expectEqual(@as(u32, 2), queue.peek().?); } test "sift up with odd indices" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; + + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; for (items) |e| { - try queue.add(e); + try queue.push(gpa, e); } const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 }; for (sorted_items) |e| { - try expectEqual(e, queue.remove()); + try expectEqual(e, queue.pop()); } } test "addSlice" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; + + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; - try queue.addSlice(items[0..]); + try queue.pushSlice(gpa, items[0..]); const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 }; for (sorted_items) |e| { - try expectEqual(e, queue.remove()); + try expectEqual(e, queue.pop()); } } test "fromOwnedSlice trivial case 0" { + const gpa = testing.allocator; + const items = [0]u32{}; - const queue_items = try testing.allocator.dupe(u32, &items); - var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {}); - defer queue.deinit(); + const queue_items = try gpa.dupe(u32, &items); + + var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {}); + defer queue.deinit(gpa); + try expectEqual(@as(usize, 0), queue.count()); - try expect(queue.removeOrNull() == null); + try expect(queue.pop() == null); } test "fromOwnedSlice trivial case 1" { + const gpa = testing.allocator; + const items = [1]u32{1}; - const queue_items = try testing.allocator.dupe(u32, &items); - var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {}); - defer queue.deinit(); + const queue_items = try gpa.dupe(u32, &items); + + var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {}); + defer queue.deinit(gpa); try expectEqual(@as(usize, 1), queue.count()); - try expectEqual(items[0], queue.remove()); - try expect(queue.removeOrNull() == null); + try expectEqual(items[0], queue.pop()); + try expect(queue.pop() == null); } test "fromOwnedSlice" { + const gpa = testing.allocator; + const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 }; - const heap_items = try testing.allocator.dupe(u32, items[0..]); - var queue = PQlt.fromOwnedSlice(testing.allocator, heap_items[0..], {}); - defer queue.deinit(); + const heap_items = try gpa.dupe(u32, items[0..]); + + var queue: MinHeap = .fromOwnedSlice(heap_items[0..], {}); + defer queue.deinit(gpa); const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 }; for (sorted_items) |e| { - try expectEqual(e, queue.remove()); + try expectEqual(e, queue.pop()); } } test "add and remove max heap" { - var queue = PQgt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(54); - try queue.add(12); - try queue.add(7); - try queue.add(23); - try queue.add(25); - try queue.add(13); - try expectEqual(@as(u32, 54), queue.remove()); - try expectEqual(@as(u32, 25), queue.remove()); - try expectEqual(@as(u32, 23), queue.remove()); - try expectEqual(@as(u32, 13), queue.remove()); - try expectEqual(@as(u32, 12), queue.remove()); - try expectEqual(@as(u32, 7), queue.remove()); + var queue: MaxHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 54); + try queue.push(gpa, 12); + try queue.push(gpa, 7); + try queue.push(gpa, 23); + try queue.push(gpa, 25); + try queue.push(gpa, 13); + try expectEqual(@as(u32, 54), queue.pop()); + try expectEqual(@as(u32, 25), queue.pop()); + try expectEqual(@as(u32, 23), queue.pop()); + try expectEqual(@as(u32, 13), queue.pop()); + try expectEqual(@as(u32, 12), queue.pop()); + try expectEqual(@as(u32, 7), queue.pop()); } test "add and remove same max heap" { - var queue = PQgt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(1); - try queue.add(1); - try queue.add(2); - try queue.add(2); - try queue.add(1); - try queue.add(1); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); + var queue: MaxHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 1); + try queue.push(gpa, 1); + try queue.push(gpa, 2); + try queue.push(gpa, 2); + try queue.push(gpa, 1); + try queue.push(gpa, 1); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); } test "iterator" { - var queue = PQlt.init(testing.allocator, {}); + const gpa = testing.allocator; + + var queue: MinHeap = .empty; var map = std.AutoHashMap(u32, void).init(testing.allocator); defer { - queue.deinit(); + queue.deinit(gpa); map.deinit(); } const items = [_]u32{ 54, 12, 7, 23, 25, 13 }; for (items) |e| { - _ = try queue.add(e); + _ = try queue.push(gpa, e); try map.put(e, {}); } @@ -485,12 +506,14 @@ test "iterator" { } test "remove at index" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; + + var queue: MinHeap = .empty; + defer queue.deinit(gpa); const items = [_]u32{ 2, 1, 8, 9, 3, 4, 5 }; for (items) |e| { - _ = try queue.add(e); + _ = try queue.push(gpa, e); } var it = queue.iterator(); @@ -501,18 +524,20 @@ test "remove at index" { idx += 1; } else unreachable; const sorted_items = [_]u32{ 1, 3, 4, 5, 8, 9 }; - try expectEqual(queue.removeIndex(two_idx), 2); + try expectEqual(queue.popIndex(two_idx), 2); var i: usize = 0; - while (queue.removeOrNull()) |n| : (i += 1) { + while (queue.pop()) |n| : (i += 1) { try expectEqual(n, sorted_items[i]); } - try expectEqual(queue.removeOrNull(), null); + try expectEqual(queue.pop(), null); } test "iterator while empty" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; + + var queue: MinHeap = .empty; + defer queue.deinit(gpa); var it = queue.iterator(); @@ -520,110 +545,124 @@ test "iterator while empty" { } test "shrinkAndFree" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.ensureTotalCapacity(4); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.ensureTotalCapacity(gpa, 4); try expect(queue.capacity() >= 4); - try queue.add(1); - try queue.add(2); - try queue.add(3); + try queue.push(gpa, 1); + try queue.push(gpa, 2); + try queue.push(gpa, 3); try expect(queue.capacity() >= 4); try expectEqual(@as(usize, 3), queue.count()); - queue.shrinkAndFree(3); + queue.shrinkAndFree(gpa, 3); try expectEqual(@as(usize, 3), queue.capacity()); try expectEqual(@as(usize, 3), queue.count()); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 3), queue.remove()); - try expect(queue.removeOrNull() == null); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 3), queue.pop()); + try expect(queue.pop() == null); } test "update min heap" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(55); - try queue.add(44); - try queue.add(11); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 55); + try queue.push(gpa, 44); + try queue.push(gpa, 11); try queue.update(55, 5); try queue.update(44, 4); try queue.update(11, 1); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 4), queue.remove()); - try expectEqual(@as(u32, 5), queue.remove()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 4), queue.pop()); + try expectEqual(@as(u32, 5), queue.pop()); } test "update same min heap" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(1); - try queue.add(1); - try queue.add(2); - try queue.add(2); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 1); + try queue.push(gpa, 1); + try queue.push(gpa, 2); + try queue.push(gpa, 2); try queue.update(1, 5); try queue.update(2, 4); - try expectEqual(@as(u32, 1), queue.remove()); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 4), queue.remove()); - try expectEqual(@as(u32, 5), queue.remove()); + try expectEqual(@as(u32, 1), queue.pop()); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 4), queue.pop()); + try expectEqual(@as(u32, 5), queue.pop()); } test "update max heap" { - var queue = PQgt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(55); - try queue.add(44); - try queue.add(11); + var queue: MaxHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 55); + try queue.push(gpa, 44); + try queue.push(gpa, 11); try queue.update(55, 5); try queue.update(44, 1); try queue.update(11, 4); - try expectEqual(@as(u32, 5), queue.remove()); - try expectEqual(@as(u32, 4), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); + try expectEqual(@as(u32, 5), queue.pop()); + try expectEqual(@as(u32, 4), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); } test "update same max heap" { - var queue = PQgt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(1); - try queue.add(1); - try queue.add(2); - try queue.add(2); + var queue: MaxHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 1); + try queue.push(gpa, 1); + try queue.push(gpa, 2); + try queue.push(gpa, 2); try queue.update(1, 5); try queue.update(2, 4); - try expectEqual(@as(u32, 5), queue.remove()); - try expectEqual(@as(u32, 4), queue.remove()); - try expectEqual(@as(u32, 2), queue.remove()); - try expectEqual(@as(u32, 1), queue.remove()); + try expectEqual(@as(u32, 5), queue.pop()); + try expectEqual(@as(u32, 4), queue.pop()); + try expectEqual(@as(u32, 2), queue.pop()); + try expectEqual(@as(u32, 1), queue.pop()); } test "update after remove" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.add(1); - try expectEqual(@as(u32, 1), queue.remove()); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); + + try queue.push(gpa, 1); + try expectEqual(@as(u32, 1), queue.pop()); try expectError(error.ElementNotFound, queue.update(1, 1)); } test "siftUp in remove" { - var queue = PQlt.init(testing.allocator, {}); - defer queue.deinit(); + const gpa = testing.allocator; - try queue.addSlice(&.{ 0, 1, 100, 2, 3, 101, 102, 4, 5, 6, 7, 103, 104, 105, 106, 8 }); + var queue: MinHeap = .empty; + defer queue.deinit(gpa); - _ = queue.removeIndex(std.mem.findScalar(u32, queue.items[0..queue.count()], 102).?); + try queue.pushSlice(gpa, &.{ 0, 1, 100, 2, 3, 101, 102, 4, 5, 6, 7, 103, 104, 105, 106, 8 }); + + _ = queue.popIndex(std.mem.findScalar(u32, queue.items[0..queue.count()], 102).?); const sorted_items = [_]u32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 103, 104, 105, 106 }; for (sorted_items) |e| { - try expectEqual(e, queue.remove()); + try expectEqual(e, queue.pop()); } } @@ -631,26 +670,28 @@ fn contextLessThan(context: []const u32, a: usize, b: usize) Order { return std.math.order(context[a], context[b]); } -const CPQlt = PriorityQueue(usize, []const u32, contextLessThan); +const MinHeapWithContext = PriorityQueue(usize, []const u32, contextLessThan); test "add and remove min heap with context comparator" { + const gpa = testing.allocator; + const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 }; - var queue = CPQlt.init(testing.allocator, context[0..]); - defer queue.deinit(); + var queue: MinHeapWithContext = .initContext(context[0..]); + defer queue.deinit(gpa); - try queue.add(0); - try queue.add(1); - try queue.add(2); - try queue.add(3); - try queue.add(4); - try queue.add(5); - try queue.add(6); - try expectEqual(@as(usize, 6), queue.remove()); - try expectEqual(@as(usize, 4), queue.remove()); - try expectEqual(@as(usize, 3), queue.remove()); - try expectEqual(@as(usize, 1), queue.remove()); - try expectEqual(@as(usize, 2), queue.remove()); - try expectEqual(@as(usize, 0), queue.remove()); - try expectEqual(@as(usize, 5), queue.remove()); + try queue.push(gpa, 0); + try queue.push(gpa, 1); + try queue.push(gpa, 2); + try queue.push(gpa, 3); + try queue.push(gpa, 4); + try queue.push(gpa, 5); + try queue.push(gpa, 6); + try expectEqual(@as(usize, 6), queue.pop()); + try expectEqual(@as(usize, 4), queue.pop()); + try expectEqual(@as(usize, 3), queue.pop()); + try expectEqual(@as(usize, 1), queue.pop()); + try expectEqual(@as(usize, 2), queue.pop()); + try expectEqual(@as(usize, 0), queue.pop()); + try expectEqual(@as(usize, 5), queue.pop()); }