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...@@ -20,31 +20,36 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
2020
21 items: []T,21 items: []T,
22 cap: usize,22 cap: usize,
23 allocator: Allocator,
24 context: Context,23 context: Context,
2524
26 /// Initialize and return a priority queue.25 /// A priority queue containing no elements.
27 pub fn init(allocator: Allocator, context: Context) Self {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 {
28 return Self{34 return Self{
29 .items = &[_]T{},35 .items = &.{},
30 .cap = 0,36 .cap = 0,
31 .allocator = allocator,
32 .context = context,37 .context = context,
33 };38 };
34 }39 }
3540
36 /// Free memory used by the queue.41 /// Free memory used by the queue.
37 pub fn deinit(self: Self) void {42 pub fn deinit(self: *Self, allocator: Allocator) void {
38 self.allocator.free(self.allocatedSlice());43 allocator.free(self.allocatedSlice());
39 }44 }
4045
41 /// Insert a new element, maintaining priority.46 /// Insert a new element, maintaining priority.
42 pub fn add(self: *Self, elem: T) !void {47 pub fn push(self: *Self, allocator: Allocator, elem: T) !void {
43 try self.ensureUnusedCapacity(1);48 try self.ensureUnusedCapacity(allocator, 1);
44 addUnchecked(self, elem);49 pushUnchecked(self, elem);
45 }50 }
4651
47 fn addUnchecked(self: *Self, elem: T) void {52 fn pushUnchecked(self: *Self, elem: T) void {
48 self.items.len += 1;53 self.items.len += 1;
49 self.items[self.items.len - 1] = elem;54 self.items[self.items.len - 1] = elem;
50 siftUp(self, self.items.len - 1);55 siftUp(self, self.items.len - 1);
...@@ -64,10 +69,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF...@@ -64,10 +69,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
64 }69 }
6570
66 /// Add each element in `items` to the queue.71 /// Add each element in `items` to the queue.
67 pub fn addSlice(self: *Self, items: []const T) !void {72 pub fn pushSlice(self: *Self, allocator: Allocator, items: []const T) !void {
68 try self.ensureUnusedCapacity(items.len);73 try self.ensureUnusedCapacity(allocator, items.len);
69 for (items) |e| {74 for (items) |e| {
70 self.addUnchecked(e);75 self.pushUnchecked(e);
71 }76 }
72 }77 }
7378
...@@ -77,22 +82,16 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF...@@ -77,22 +82,16 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
77 return if (self.items.len > 0) self.items[0] else null;82 return if (self.items.len > 0) self.items[0] else null;
78 }83 }
7984
80 /// Pop the highest priority element from the queue. Returns85 /// Remove and return the highest priority element from the queue.
81 /// `null` if empty.86 /// Returns `null` if empty.
82 pub fn removeOrNull(self: *Self) ?T {87 pub fn pop(self: *Self) ?T {
83 return if (self.items.len > 0) self.remove() else null;88 return if (self.items.len > 0) self.popIndex(0) 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);
90 }89 }
9190
92 /// Remove and return element at index. Indices are in the91 /// Remove and return element at index. Indices are in the
93 /// same order as iterator, which is not necessarily priority92 /// same order as iterator, which is not necessarily priority
94 /// order.93 /// order.
95 pub fn removeIndex(self: *Self, index: usize) T {94 pub fn popIndex(self: *Self, index: usize) T {
96 assert(self.items.len > index);95 assert(self.items.len > index);
97 const last = self.items[self.items.len - 1];96 const last = self.items[self.items.len - 1];
98 const item = self.items[index];97 const item = self.items[index];
...@@ -158,11 +157,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF...@@ -158,11 +157,10 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
158 /// PriorityQueue takes ownership of the passed in slice. The slice must have been157 /// PriorityQueue takes ownership of the passed in slice. The slice must have been
159 /// allocated with `allocator`.158 /// allocated with `allocator`.
160 /// Deinitialize with `deinit`.159 /// Deinitialize with `deinit`.
161 pub fn fromOwnedSlice(allocator: Allocator, items: []T, context: Context) Self {160 pub fn fromOwnedSlice(items: []T, context: Context) Self {
162 var self = Self{161 var self = Self{
163 .items = items,162 .items = items,
164 .cap = items.len,163 .cap = items.len,
165 .allocator = allocator,
166 .context = context,164 .context = context,
167 };165 };
168166
...@@ -175,39 +173,42 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF...@@ -175,39 +173,42 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
175 }173 }
176174
177 /// Ensure that the queue can fit at least `new_capacity` items.175 /// 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 {
179 var better_capacity = self.cap;177 var better_capacity = self.cap;
180 if (better_capacity >= new_capacity) return;178 if (better_capacity >= new_capacity) return;
181 while (true) {179 while (true) {
182 better_capacity += better_capacity / 2 + 8;180 better_capacity += better_capacity / 2 + 8;
183 if (better_capacity >= new_capacity) break;181 if (better_capacity >= new_capacity) break;
184 }182 }
185 try self.ensureTotalCapacityPrecise(better_capacity);183 try self.ensureTotalCapacityPrecise(allocator, better_capacity);
186 }184 }
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 {
189 if (self.capacity() >= new_capacity) return;190 if (self.capacity() >= new_capacity) return;
190191
191 const old_memory = self.allocatedSlice();192 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);
193 self.items.ptr = new_memory.ptr;194 self.items.ptr = new_memory.ptr;
194 self.cap = new_memory.len;195 self.cap = new_memory.len;
195 }196 }
196197
197 /// Ensure that the queue can fit at least `additional_count` **more** item.198 /// Ensure that the queue can fit at least `additional_count` **more** item.
198 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void {199 pub fn ensureUnusedCapacity(self: *Self, allocator: Allocator, additional_count: usize) !void {
199 return self.ensureTotalCapacity(self.items.len + additional_count);200 return self.ensureTotalCapacity(allocator, self.items.len + additional_count);
200 }201 }
201202
202 /// Reduce allocated capacity to `new_capacity`.203 /// 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 {
204 assert(new_capacity <= self.cap);205 assert(new_capacity <= self.cap);
205206
206 // Cannot shrink to smaller than the current queue size without invalidating the heap property207 // Cannot shrink to smaller than the current queue size without invalidating the heap property
207 assert(new_capacity >= self.items.len);208 assert(new_capacity >= self.items.len);
208209
209 const old_memory = self.allocatedSlice();210 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) {
211 error.OutOfMemory => { // no problem, capacity is still correct then.212 error.OutOfMemory => { // no problem, capacity is still correct then.
212 return;213 return;
213 },214 },
...@@ -217,16 +218,20 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF...@@ -217,16 +218,20 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
217 self.cap = new_memory.len;218 self.cap = new_memory.len;
218 }219 }
219220
221 /// Remove all elements from the items slice.
220 pub fn clearRetainingCapacity(self: *Self) void {222 pub fn clearRetainingCapacity(self: *Self) void {
221 self.items.len = 0;223 self.items.len = 0;
222 }224 }
223225
224 pub fn clearAndFree(self: *Self) void {226 /// Invalidates all element pointers.
225 self.allocator.free(self.allocatedSlice());227 pub fn clearAndFree(self: *Self, allocator: Allocator) void {
228 allocator.free(self.allocatedSlice());
226 self.items.len = 0;229 self.items.len = 0;
227 self.cap = 0;230 self.cap = 0;
228 }231 }
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`.
230 pub fn update(self: *Self, elem: T, new_elem: T) !void {235 pub fn update(self: *Self, elem: T, new_elem: T) !void {
231 const update_index = blk: {236 const update_index = blk: {
232 var idx: usize = 0;237 var idx: usize = 0;
...@@ -270,22 +275,6 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF...@@ -270,22 +275,6 @@ pub fn PriorityQueue(comptime T: type, comptime Context: type, comptime compareF
270 .count = 0,275 .count = 0,
271 };276 };
272 }277 }
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 }
289 };278 };
290}279}
291280
...@@ -298,181 +287,213 @@ fn greaterThan(context: void, a: u32, b: u32) Order {...@@ -298,181 +287,213 @@ fn greaterThan(context: void, a: u32, b: u32) Order {
298 return lessThan(context, a, b).invert();287 return lessThan(context, a, b).invert();
299}288}
300289
301const PQlt = PriorityQueue(u32, void, lessThan);290const MinHeap = PriorityQueue(u32, void, lessThan);
302const PQgt = PriorityQueue(u32, void, greaterThan);291const MaxHeap = PriorityQueue(u32, void, greaterThan);
303292
304test "add and remove min heap" {293test "add and remove min heap" {
305 var queue = PQlt.init(testing.allocator, {});294 const gpa = testing.allocator;
306 defer queue.deinit();295
307296 var queue: MinHeap = .empty;
308 try queue.add(54);297 defer queue.deinit(gpa);
309 try queue.add(12);298
310 try queue.add(7);299 try queue.push(gpa, 54);
311 try queue.add(23);300 try queue.push(gpa, 12);
312 try queue.add(25);301 try queue.push(gpa, 7);
313 try queue.add(13);302 try queue.push(gpa, 23);
314 try expectEqual(@as(u32, 7), queue.remove());303 try queue.push(gpa, 25);
315 try expectEqual(@as(u32, 12), queue.remove());304 try queue.push(gpa, 13);
316 try expectEqual(@as(u32, 13), queue.remove());305 try expectEqual(@as(u32, 7), queue.pop());
317 try expectEqual(@as(u32, 23), queue.remove());306 try expectEqual(@as(u32, 12), queue.pop());
318 try expectEqual(@as(u32, 25), queue.remove());307 try expectEqual(@as(u32, 13), queue.pop());
319 try expectEqual(@as(u32, 54), queue.remove());308 try expectEqual(@as(u32, 23), queue.pop());
309 try expectEqual(@as(u32, 25), queue.pop());
310 try expectEqual(@as(u32, 54), queue.pop());
320}311}
321312
322test "add and remove same min heap" {313test "add and remove same min heap" {
323 var queue = PQlt.init(testing.allocator, {});314 const gpa = testing.allocator;
324 defer queue.deinit();315
325316 var queue: MinHeap = .empty;
326 try queue.add(1);317 defer queue.deinit(gpa);
327 try queue.add(1);318
328 try queue.add(2);319 try queue.push(gpa, 1);
329 try queue.add(2);320 try queue.push(gpa, 1);
330 try queue.add(1);321 try queue.push(gpa, 2);
331 try queue.add(1);322 try queue.push(gpa, 2);
332 try expectEqual(@as(u32, 1), queue.remove());323 try queue.push(gpa, 1);
333 try expectEqual(@as(u32, 1), queue.remove());324 try queue.push(gpa, 1);
334 try expectEqual(@as(u32, 1), queue.remove());325 try expectEqual(@as(u32, 1), queue.pop());
335 try expectEqual(@as(u32, 1), queue.remove());326 try expectEqual(@as(u32, 1), queue.pop());
336 try expectEqual(@as(u32, 2), queue.remove());327 try expectEqual(@as(u32, 1), queue.pop());
337 try expectEqual(@as(u32, 2), queue.remove());328 try expectEqual(@as(u32, 1), queue.pop());
329 try expectEqual(@as(u32, 2), queue.pop());
330 try expectEqual(@as(u32, 2), queue.pop());
338}331}
339332
340test "removeOrNull on empty" {333test "removeOrNull on empty" {
341 var queue = PQlt.init(testing.allocator, {});334 const gpa = testing.allocator;
342 defer queue.deinit();335
336 var queue: MinHeap = .empty;
337 defer queue.deinit(gpa);
343338
344 try expect(queue.removeOrNull() == null);339 try expect(queue.pop() == null);
345}340}
346341
347test "edge case 3 elements" {342test "edge case 3 elements" {
348 var queue = PQlt.init(testing.allocator, {});343 const gpa = testing.allocator;
349 defer queue.deinit();344
350345 var queue: MinHeap = .empty;
351 try queue.add(9);346 defer queue.deinit(gpa);
352 try queue.add(3);347
353 try queue.add(2);348 try queue.push(gpa, 9);
354 try expectEqual(@as(u32, 2), queue.remove());349 try queue.push(gpa, 3);
355 try expectEqual(@as(u32, 3), queue.remove());350 try queue.push(gpa, 2);
356 try expectEqual(@as(u32, 9), queue.remove());351 try expectEqual(@as(u32, 2), queue.pop());
352 try expectEqual(@as(u32, 3), queue.pop());
353 try expectEqual(@as(u32, 9), queue.pop());
357}354}
358355
359test "peek" {356test "peek" {
360 var queue = PQlt.init(testing.allocator, {});357 const gpa = testing.allocator;
361 defer queue.deinit();358
359 var queue: MinHeap = .empty;
360 defer queue.deinit(gpa);
362361
363 try expect(queue.peek() == null);362 try expect(queue.peek() == null);
364 try queue.add(9);363 try queue.push(gpa, 9);
365 try queue.add(3);364 try queue.push(gpa, 3);
366 try queue.add(2);365 try queue.push(gpa, 2);
367 try expectEqual(@as(u32, 2), queue.peek().?);366 try expectEqual(@as(u32, 2), queue.peek().?);
368 try expectEqual(@as(u32, 2), queue.peek().?);367 try expectEqual(@as(u32, 2), queue.peek().?);
369}368}
370369
371test "sift up with odd indices" {370test "sift up with odd indices" {
372 var queue = PQlt.init(testing.allocator, {});371 const gpa = testing.allocator;
373 defer queue.deinit();372
373 var queue: MinHeap = .empty;
374 defer queue.deinit(gpa);
375
374 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };376 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
375 for (items) |e| {377 for (items) |e| {
376 try queue.add(e);378 try queue.push(gpa, e);
377 }379 }
378380
379 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };381 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
380 for (sorted_items) |e| {382 for (sorted_items) |e| {
381 try expectEqual(e, queue.remove());383 try expectEqual(e, queue.pop());
382 }384 }
383}385}
384386
385test "addSlice" {387test "addSlice" {
386 var queue = PQlt.init(testing.allocator, {});388 const gpa = testing.allocator;
387 defer queue.deinit();389
390 var queue: MinHeap = .empty;
391 defer queue.deinit(gpa);
392
388 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };393 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
391 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };396 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
392 for (sorted_items) |e| {397 for (sorted_items) |e| {
393 try expectEqual(e, queue.remove());398 try expectEqual(e, queue.pop());
394 }399 }
395}400}
396401
397test "fromOwnedSlice trivial case 0" {402test "fromOwnedSlice trivial case 0" {
403 const gpa = testing.allocator;
404
398 const items = [0]u32{};405 const items = [0]u32{};
399 const queue_items = try testing.allocator.dupe(u32, &items);406 const queue_items = try gpa.dupe(u32, &items);
400 var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {});407
401 defer queue.deinit();408 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
409 defer queue.deinit(gpa);
410
402 try expectEqual(@as(usize, 0), queue.count());411 try expectEqual(@as(usize, 0), queue.count());
403 try expect(queue.removeOrNull() == null);412 try expect(queue.pop() == null);
404}413}
405414
406test "fromOwnedSlice trivial case 1" {415test "fromOwnedSlice trivial case 1" {
416 const gpa = testing.allocator;
417
407 const items = [1]u32{1};418 const items = [1]u32{1};
408 const queue_items = try testing.allocator.dupe(u32, &items);419 const queue_items = try gpa.dupe(u32, &items);
409 var queue = PQlt.fromOwnedSlice(testing.allocator, queue_items[0..], {});420
410 defer queue.deinit();421 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
422 defer queue.deinit(gpa);
411423
412 try expectEqual(@as(usize, 1), queue.count());424 try expectEqual(@as(usize, 1), queue.count());
413 try expectEqual(items[0], queue.remove());425 try expectEqual(items[0], queue.pop());
414 try expect(queue.removeOrNull() == null);426 try expect(queue.pop() == null);
415}427}
416428
417test "fromOwnedSlice" {429test "fromOwnedSlice" {
430 const gpa = testing.allocator;
431
418 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };432 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..]);433 const heap_items = try gpa.dupe(u32, items[0..]);
420 var queue = PQlt.fromOwnedSlice(testing.allocator, heap_items[0..], {});434
421 defer queue.deinit();435 var queue: MinHeap = .fromOwnedSlice(heap_items[0..], {});
436 defer queue.deinit(gpa);
422437
423 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };438 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
424 for (sorted_items) |e| {439 for (sorted_items) |e| {
425 try expectEqual(e, queue.remove());440 try expectEqual(e, queue.pop());
426 }441 }
427}442}
428443
429test "add and remove max heap" {444test "add and remove max heap" {
430 var queue = PQgt.init(testing.allocator, {});445 const gpa = testing.allocator;
431 defer queue.deinit();446
432447 var queue: MaxHeap = .empty;
433 try queue.add(54);448 defer queue.deinit(gpa);
434 try queue.add(12);449
435 try queue.add(7);450 try queue.push(gpa, 54);
436 try queue.add(23);451 try queue.push(gpa, 12);
437 try queue.add(25);452 try queue.push(gpa, 7);
438 try queue.add(13);453 try queue.push(gpa, 23);
439 try expectEqual(@as(u32, 54), queue.remove());454 try queue.push(gpa, 25);
440 try expectEqual(@as(u32, 25), queue.remove());455 try queue.push(gpa, 13);
441 try expectEqual(@as(u32, 23), queue.remove());456 try expectEqual(@as(u32, 54), queue.pop());
442 try expectEqual(@as(u32, 13), queue.remove());457 try expectEqual(@as(u32, 25), queue.pop());
443 try expectEqual(@as(u32, 12), queue.remove());458 try expectEqual(@as(u32, 23), queue.pop());
444 try expectEqual(@as(u32, 7), queue.remove());459 try expectEqual(@as(u32, 13), queue.pop());
460 try expectEqual(@as(u32, 12), queue.pop());
461 try expectEqual(@as(u32, 7), queue.pop());
445}462}
446463
447test "add and remove same max heap" {464test "add and remove same max heap" {
448 var queue = PQgt.init(testing.allocator, {});465 const gpa = testing.allocator;
449 defer queue.deinit();466
450467 var queue: MaxHeap = .empty;
451 try queue.add(1);468 defer queue.deinit(gpa);
452 try queue.add(1);469
453 try queue.add(2);470 try queue.push(gpa, 1);
454 try queue.add(2);471 try queue.push(gpa, 1);
455 try queue.add(1);472 try queue.push(gpa, 2);
456 try queue.add(1);473 try queue.push(gpa, 2);
457 try expectEqual(@as(u32, 2), queue.remove());474 try queue.push(gpa, 1);
458 try expectEqual(@as(u32, 2), queue.remove());475 try queue.push(gpa, 1);
459 try expectEqual(@as(u32, 1), queue.remove());476 try expectEqual(@as(u32, 2), queue.pop());
460 try expectEqual(@as(u32, 1), queue.remove());477 try expectEqual(@as(u32, 2), queue.pop());
461 try expectEqual(@as(u32, 1), queue.remove());478 try expectEqual(@as(u32, 1), queue.pop());
462 try expectEqual(@as(u32, 1), queue.remove());479 try expectEqual(@as(u32, 1), queue.pop());
480 try expectEqual(@as(u32, 1), queue.pop());
481 try expectEqual(@as(u32, 1), queue.pop());
463}482}
464483
465test "iterator" {484test "iterator" {
466 var queue = PQlt.init(testing.allocator, {});485 const gpa = testing.allocator;
486
487 var queue: MinHeap = .empty;
467 var map = std.AutoHashMap(u32, void).init(testing.allocator);488 var map = std.AutoHashMap(u32, void).init(testing.allocator);
468 defer {489 defer {
469 queue.deinit();490 queue.deinit(gpa);
470 map.deinit();491 map.deinit();
471 }492 }
472493
473 const items = [_]u32{ 54, 12, 7, 23, 25, 13 };494 const items = [_]u32{ 54, 12, 7, 23, 25, 13 };
474 for (items) |e| {495 for (items) |e| {
475 _ = try queue.add(e);496 _ = try queue.push(gpa, e);
476 try map.put(e, {});497 try map.put(e, {});
477 }498 }
478499
...@@ -485,12 +506,14 @@ test "iterator" {...@@ -485,12 +506,14 @@ test "iterator" {
485}506}
486507
487test "remove at index" {508test "remove at index" {
488 var queue = PQlt.init(testing.allocator, {});509 const gpa = testing.allocator;
489 defer queue.deinit();510
511 var queue: MinHeap = .empty;
512 defer queue.deinit(gpa);
490513
491 const items = [_]u32{ 2, 1, 8, 9, 3, 4, 5 };514 const items = [_]u32{ 2, 1, 8, 9, 3, 4, 5 };
492 for (items) |e| {515 for (items) |e| {
493 _ = try queue.add(e);516 _ = try queue.push(gpa, e);
494 }517 }
495518
496 var it = queue.iterator();519 var it = queue.iterator();
...@@ -501,18 +524,20 @@ test "remove at index" {...@@ -501,18 +524,20 @@ test "remove at index" {
501 idx += 1;524 idx += 1;
502 } else unreachable;525 } else unreachable;
503 const sorted_items = [_]u32{ 1, 3, 4, 5, 8, 9 };526 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
506 var i: usize = 0;529 var i: usize = 0;
507 while (queue.removeOrNull()) |n| : (i += 1) {530 while (queue.pop()) |n| : (i += 1) {
508 try expectEqual(n, sorted_items[i]);531 try expectEqual(n, sorted_items[i]);
509 }532 }
510 try expectEqual(queue.removeOrNull(), null);533 try expectEqual(queue.pop(), null);
511}534}
512535
513test "iterator while empty" {536test "iterator while empty" {
514 var queue = PQlt.init(testing.allocator, {});537 const gpa = testing.allocator;
515 defer queue.deinit();538
539 var queue: MinHeap = .empty;
540 defer queue.deinit(gpa);
516541
517 var it = queue.iterator();542 var it = queue.iterator();
518543
...@@ -520,110 +545,124 @@ test "iterator while empty" {...@@ -520,110 +545,124 @@ test "iterator while empty" {
520}545}
521546
522test "shrinkAndFree" {547test "shrinkAndFree" {
523 var queue = PQlt.init(testing.allocator, {});548 const gpa = testing.allocator;
524 defer queue.deinit();549
550 var queue: MinHeap = .empty;
551 defer queue.deinit(gpa);
525552
526 try queue.ensureTotalCapacity(4);553 try queue.ensureTotalCapacity(gpa, 4);
527 try expect(queue.capacity() >= 4);554 try expect(queue.capacity() >= 4);
528555
529 try queue.add(1);556 try queue.push(gpa, 1);
530 try queue.add(2);557 try queue.push(gpa, 2);
531 try queue.add(3);558 try queue.push(gpa, 3);
532 try expect(queue.capacity() >= 4);559 try expect(queue.capacity() >= 4);
533 try expectEqual(@as(usize, 3), queue.count());560 try expectEqual(@as(usize, 3), queue.count());
534561
535 queue.shrinkAndFree(3);562 queue.shrinkAndFree(gpa, 3);
536 try expectEqual(@as(usize, 3), queue.capacity());563 try expectEqual(@as(usize, 3), queue.capacity());
537 try expectEqual(@as(usize, 3), queue.count());564 try expectEqual(@as(usize, 3), queue.count());
538565
539 try expectEqual(@as(u32, 1), queue.remove());566 try expectEqual(@as(u32, 1), queue.pop());
540 try expectEqual(@as(u32, 2), queue.remove());567 try expectEqual(@as(u32, 2), queue.pop());
541 try expectEqual(@as(u32, 3), queue.remove());568 try expectEqual(@as(u32, 3), queue.pop());
542 try expect(queue.removeOrNull() == null);569 try expect(queue.pop() == null);
543}570}
544571
545test "update min heap" {572test "update min heap" {
546 var queue = PQlt.init(testing.allocator, {});573 const gpa = testing.allocator;
547 defer queue.deinit();574
575 var queue: MinHeap = .empty;
576 defer queue.deinit(gpa);
548577
549 try queue.add(55);578 try queue.push(gpa, 55);
550 try queue.add(44);579 try queue.push(gpa, 44);
551 try queue.add(11);580 try queue.push(gpa, 11);
552 try queue.update(55, 5);581 try queue.update(55, 5);
553 try queue.update(44, 4);582 try queue.update(44, 4);
554 try queue.update(11, 1);583 try queue.update(11, 1);
555 try expectEqual(@as(u32, 1), queue.remove());584 try expectEqual(@as(u32, 1), queue.pop());
556 try expectEqual(@as(u32, 4), queue.remove());585 try expectEqual(@as(u32, 4), queue.pop());
557 try expectEqual(@as(u32, 5), queue.remove());586 try expectEqual(@as(u32, 5), queue.pop());
558}587}
559588
560test "update same min heap" {589test "update same min heap" {
561 var queue = PQlt.init(testing.allocator, {});590 const gpa = testing.allocator;
562 defer queue.deinit();
563591
564 try queue.add(1);592 var queue: MinHeap = .empty;
565 try queue.add(1);593 defer queue.deinit(gpa);
566 try queue.add(2);594
567 try queue.add(2);595 try queue.push(gpa, 1);
596 try queue.push(gpa, 1);
597 try queue.push(gpa, 2);
598 try queue.push(gpa, 2);
568 try queue.update(1, 5);599 try queue.update(1, 5);
569 try queue.update(2, 4);600 try queue.update(2, 4);
570 try expectEqual(@as(u32, 1), queue.remove());601 try expectEqual(@as(u32, 1), queue.pop());
571 try expectEqual(@as(u32, 2), queue.remove());602 try expectEqual(@as(u32, 2), queue.pop());
572 try expectEqual(@as(u32, 4), queue.remove());603 try expectEqual(@as(u32, 4), queue.pop());
573 try expectEqual(@as(u32, 5), queue.remove());604 try expectEqual(@as(u32, 5), queue.pop());
574}605}
575606
576test "update max heap" {607test "update max heap" {
577 var queue = PQgt.init(testing.allocator, {});608 const gpa = testing.allocator;
578 defer queue.deinit();609
610 var queue: MaxHeap = .empty;
611 defer queue.deinit(gpa);
579612
580 try queue.add(55);613 try queue.push(gpa, 55);
581 try queue.add(44);614 try queue.push(gpa, 44);
582 try queue.add(11);615 try queue.push(gpa, 11);
583 try queue.update(55, 5);616 try queue.update(55, 5);
584 try queue.update(44, 1);617 try queue.update(44, 1);
585 try queue.update(11, 4);618 try queue.update(11, 4);
586 try expectEqual(@as(u32, 5), queue.remove());619 try expectEqual(@as(u32, 5), queue.pop());
587 try expectEqual(@as(u32, 4), queue.remove());620 try expectEqual(@as(u32, 4), queue.pop());
588 try expectEqual(@as(u32, 1), queue.remove());621 try expectEqual(@as(u32, 1), queue.pop());
589}622}
590623
591test "update same max heap" {624test "update same max heap" {
592 var queue = PQgt.init(testing.allocator, {});625 const gpa = testing.allocator;
593 defer queue.deinit();
594626
595 try queue.add(1);627 var queue: MaxHeap = .empty;
596 try queue.add(1);628 defer queue.deinit(gpa);
597 try queue.add(2);629
598 try queue.add(2);630 try queue.push(gpa, 1);
631 try queue.push(gpa, 1);
632 try queue.push(gpa, 2);
633 try queue.push(gpa, 2);
599 try queue.update(1, 5);634 try queue.update(1, 5);
600 try queue.update(2, 4);635 try queue.update(2, 4);
601 try expectEqual(@as(u32, 5), queue.remove());636 try expectEqual(@as(u32, 5), queue.pop());
602 try expectEqual(@as(u32, 4), queue.remove());637 try expectEqual(@as(u32, 4), queue.pop());
603 try expectEqual(@as(u32, 2), queue.remove());638 try expectEqual(@as(u32, 2), queue.pop());
604 try expectEqual(@as(u32, 1), queue.remove());639 try expectEqual(@as(u32, 1), queue.pop());
605}640}
606641
607test "update after remove" {642test "update after remove" {
608 var queue = PQlt.init(testing.allocator, {});643 const gpa = testing.allocator;
609 defer queue.deinit();644
645 var queue: MinHeap = .empty;
646 defer queue.deinit(gpa);
610647
611 try queue.add(1);648 try queue.push(gpa, 1);
612 try expectEqual(@as(u32, 1), queue.remove());649 try expectEqual(@as(u32, 1), queue.pop());
613 try expectError(error.ElementNotFound, queue.update(1, 1));650 try expectError(error.ElementNotFound, queue.update(1, 1));
614}651}
615652
616test "siftUp in remove" {653test "siftUp in remove" {
617 var queue = PQlt.init(testing.allocator, {});654 const gpa = testing.allocator;
618 defer queue.deinit();
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
624 const sorted_items = [_]u32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 103, 104, 105, 106 };663 const sorted_items = [_]u32{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 103, 104, 105, 106 };
625 for (sorted_items) |e| {664 for (sorted_items) |e| {
626 try expectEqual(e, queue.remove());665 try expectEqual(e, queue.pop());
627 }666 }
628}667}
629668
...@@ -631,26 +670,28 @@ fn contextLessThan(context: []const u32, a: usize, b: usize) Order {...@@ -631,26 +670,28 @@ fn contextLessThan(context: []const u32, a: usize, b: usize) Order {
631 return std.math.order(context[a], context[b]);670 return std.math.order(context[a], context[b]);
632}671}
633672
634const CPQlt = PriorityQueue(usize, []const u32, contextLessThan);673const MinHeapWithContext = PriorityQueue(usize, []const u32, contextLessThan);
635674
636test "add and remove min heap with context comparator" {675test "add and remove min heap with context comparator" {
676 const gpa = testing.allocator;
677
637 const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };678 const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };
638679
639 var queue = CPQlt.init(testing.allocator, context[0..]);680 var queue: MinHeapWithContext = .initContext(context[0..]);
640 defer queue.deinit();681 defer queue.deinit(gpa);
641682
642 try queue.add(0);683 try queue.push(gpa, 0);
643 try queue.add(1);684 try queue.push(gpa, 1);
644 try queue.add(2);685 try queue.push(gpa, 2);
645 try queue.add(3);686 try queue.push(gpa, 3);
646 try queue.add(4);687 try queue.push(gpa, 4);
647 try queue.add(5);688 try queue.push(gpa, 5);
648 try queue.add(6);689 try queue.push(gpa, 6);
649 try expectEqual(@as(usize, 6), queue.remove());690 try expectEqual(@as(usize, 6), queue.pop());
650 try expectEqual(@as(usize, 4), queue.remove());691 try expectEqual(@as(usize, 4), queue.pop());
651 try expectEqual(@as(usize, 3), queue.remove());692 try expectEqual(@as(usize, 3), queue.pop());
652 try expectEqual(@as(usize, 1), queue.remove());693 try expectEqual(@as(usize, 1), queue.pop());
653 try expectEqual(@as(usize, 2), queue.remove());694 try expectEqual(@as(usize, 2), queue.pop());
654 try expectEqual(@as(usize, 0), queue.remove());695 try expectEqual(@as(usize, 0), queue.pop());
655 try expectEqual(@as(usize, 5), queue.remove());696 try expectEqual(@as(usize, 5), queue.pop());
656}697}