authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-20 07:11:57+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-20 07:11:57+01:00
log6a9510c0eb85434f75730f512f4d9e4bed5cfcb3
tree2cf5214166726ecabf1218a67d58a2b2f5ca1ef5
parent14d06330e0b85dbf9dbd2023d58d2af75a150bcc
parent5140455264347f8bf869edae71faa8848e92dabd

Merge pull request 'Make `std.PriorityDequeue` an unmanaged container' (#31273) from saurabh/zig:unmanaged-priority-dequeue into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31273

1 files changed, 383 insertions(+), 324 deletions(-)

lib/std/priority_dequeue.zig+383-324
......@@ -21,39 +21,44 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
2121
2222 items: []T,
2323 len: usize,
24 allocator: Allocator,
2524 context: Context,
2625
27 /// Initialize and return a new priority dequeue.
28 pub fn init(allocator: Allocator, context: Context) Self {
26 /// A priority dequeue containing no elements.
27 pub const empty: Self = .{
28 .items = &.{},
29 .len = 0,
30 .context = undefined,
31 };
32
33 /// Initialize and return a new priority dequeue with context.
34 pub fn initContext(context: Context) Self {
2935 return Self{
30 .items = &[_]T{},
36 .items = &.{},
3137 .len = 0,
32 .allocator = allocator,
3338 .context = context,
3439 };
3540 }
3641
3742 /// Free memory used by the dequeue.
38 pub fn deinit(self: Self) void {
39 self.allocator.free(self.items);
43 pub fn deinit(self: Self, allocator: Allocator) void {
44 allocator.free(self.items);
4045 }
4146
4247 /// Insert a new element, maintaining priority.
43 pub fn add(self: *Self, elem: T) !void {
44 try self.ensureUnusedCapacity(1);
45 addUnchecked(self, elem);
48 pub fn push(self: *Self, allocator: Allocator, elem: T) !void {
49 try self.ensureUnusedCapacity(allocator, 1);
50 pushUnchecked(self, elem);
4651 }
4752
4853 /// Add each element in `items` to the dequeue.
49 pub fn addSlice(self: *Self, items: []const T) !void {
50 try self.ensureUnusedCapacity(items.len);
54 pub fn pushSlice(self: *Self, allocator: Allocator, items: []const T) !void {
55 try self.ensureUnusedCapacity(allocator, items.len);
5156 for (items) |e| {
52 self.addUnchecked(e);
57 self.pushUnchecked(e);
5358 }
5459 }
5560
56 fn addUnchecked(self: *Self, elem: T) void {
61 fn pushUnchecked(self: *Self, elem: T) void {
5762 self.items[self.len] = elem;
5863
5964 if (self.len > 0) {
......@@ -151,34 +156,20 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
151156 return self.bestItemAtIndices(1, 2, .gt).index;
152157 }
153158
154 /// Pop the smallest element from the dequeue. Returns
155 /// `null` if empty.
156 pub fn removeMinOrNull(self: *Self) ?T {
157 return if (self.len > 0) self.removeMin() else null;
158 }
159
160 /// Remove and return the smallest element from the
161 /// dequeue.
162 pub fn removeMin(self: *Self) T {
163 return self.removeIndex(0);
164 }
165
166 /// Pop the largest element from the dequeue. Returns
167 /// `null` if empty.
168 pub fn removeMaxOrNull(self: *Self) ?T {
169 return if (self.len > 0) self.removeMax() else null;
159 /// Remove and return the smallest element from the dequeue, or `null` if empty
160 pub fn popMin(self: *Self) ?T {
161 return if (self.len > 0) self.popIndex(0) else null;
170162 }
171163
172 /// Remove and return the largest element from the
173 /// dequeue.
174 pub fn removeMax(self: *Self) T {
175 return self.removeIndex(self.maxIndex().?);
164 /// Remove and return the largest element from the dequeue, or `null` if empty
165 pub fn popMax(self: *Self) ?T {
166 return if (self.len > 0) self.popIndex(self.maxIndex().?) else null;
176167 }
177168
178169 /// Remove and return element at index. Indices are in the
179170 /// same order as iterator, which is not necessarily priority
180171 /// order.
181 pub fn removeIndex(self: *Self, index: usize) T {
172 pub fn popIndex(self: *Self, index: usize) T {
182173 assert(self.len > index);
183174 const item = self.items[index];
184175 const last = self.items[self.len - 1];
......@@ -333,14 +324,12 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
333324 return self.items.len;
334325 }
335326
336 /// Dequeue takes ownership of the passed in slice. The slice must have been
337 /// allocated with `allocator`.
338 /// De-initialize with `deinit`.
339 pub fn fromOwnedSlice(allocator: Allocator, items: []T, context: Context) Self {
327 /// Dequeue takes ownership of the passed in slice. The slice must be de-initialize
328 /// with `deinit`.
329 pub fn fromOwnedSlice(items: []T, context: Context) Self {
340330 var queue = Self{
341331 .items = items,
342332 .len = items.len,
343 .allocator = allocator,
344333 .context = context,
345334 };
346335
......@@ -356,29 +345,29 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
356345 }
357346
358347 /// Ensure that the dequeue can fit at least `new_capacity` items.
359 pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void {
348 pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) !void {
360349 var better_capacity = self.capacity();
361350 if (better_capacity >= new_capacity) return;
362351 while (true) {
363352 better_capacity += better_capacity / 2 + 8;
364353 if (better_capacity >= new_capacity) break;
365354 }
366 self.items = try self.allocator.realloc(self.items, better_capacity);
355 self.items = try allocator.realloc(self.items, better_capacity);
367356 }
368357
369358 /// Ensure that the dequeue can fit at least `additional_count` **more** items.
370 pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) !void {
371 return self.ensureTotalCapacity(self.len + additional_count);
359 pub fn ensureUnusedCapacity(self: *Self, allocator: Allocator, additional_count: usize) !void {
360 return self.ensureTotalCapacity(allocator, self.len + additional_count);
372361 }
373362
374363 /// Reduce allocated capacity to `new_len`.
375 pub fn shrinkAndFree(self: *Self, new_len: usize) void {
364 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {
376365 assert(new_len <= self.items.len);
377366
378367 // Cannot shrink to smaller than the current queue size without invalidating the heap property
379368 assert(new_len >= self.len);
380369
381 self.items = self.allocator.realloc(self.items[0..], new_len) catch |e| switch (e) {
370 self.items = allocator.realloc(self.items[0..], new_len) catch |e| switch (e) {
382371 error.OutOfMemory => { // no problem, capacity is still correct then.
383372 self.items.len = new_len;
384373 return;
......@@ -395,8 +384,8 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
395384 }
396385 return error.ElementNotFound;
397386 };
398 _ = self.removeIndex(old_index);
399 self.addUnchecked(new_elem);
387 _ = self.popIndex(old_index);
388 self.pushUnchecked(new_elem);
400389 }
401390
402391 pub const Iterator = struct {
......@@ -460,33 +449,40 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
460449 };
461450}
462451
452/// If a min heap is constructed from slice `{5, 8, 2, 9, 7, 1, 4, 4}` using this
453/// method, then the elements will be in order: {1, 2, 4, 4, 5, 7, 8, 9}
463454fn lessThanComparison(context: void, a: u32, b: u32) Order {
464455 _ = context;
465456 return std.math.order(a, b);
466457}
467458
468const PDQ = PriorityDequeue(u32, void, lessThanComparison);
469
470test "add and remove min" {
471 var queue = PDQ.init(testing.allocator, {});
472 defer queue.deinit();
473
474 try queue.add(54);
475 try queue.add(12);
476 try queue.add(7);
477 try queue.add(23);
478 try queue.add(25);
479 try queue.add(13);
480
481 try expectEqual(@as(u32, 7), queue.removeMin());
482 try expectEqual(@as(u32, 12), queue.removeMin());
483 try expectEqual(@as(u32, 13), queue.removeMin());
484 try expectEqual(@as(u32, 23), queue.removeMin());
485 try expectEqual(@as(u32, 25), queue.removeMin());
486 try expectEqual(@as(u32, 54), queue.removeMin());
459/// Elements with lower priority will be removed first
460const MinHeap = PriorityDequeue(u32, void, lessThanComparison);
461
462test "push and pop min in min heap" {
463 const gpa = std.testing.allocator;
464
465 var queue: MinHeap = .empty;
466 defer queue.deinit(gpa);
467
468 try queue.push(gpa, 54);
469 try queue.push(gpa, 12);
470 try queue.push(gpa, 7);
471 try queue.push(gpa, 23);
472 try queue.push(gpa, 25);
473 try queue.push(gpa, 13);
474
475 try expectEqual(@as(u32, 7), queue.popMin());
476 try expectEqual(@as(u32, 12), queue.popMin());
477 try expectEqual(@as(u32, 13), queue.popMin());
478 try expectEqual(@as(u32, 23), queue.popMin());
479 try expectEqual(@as(u32, 25), queue.popMin());
480 try expectEqual(@as(u32, 54), queue.popMin());
487481}
488482
489test "add and remove min structs" {
483test "push and pop min structs" {
484 const gpa = std.testing.allocator;
485
490486 const S = struct {
491487 size: u32,
492488 };
......@@ -495,310 +491,360 @@ test "add and remove min structs" {
495491 _ = context;
496492 return std.math.order(a.size, b.size);
497493 }
498 }.order).init(testing.allocator, {});
499 defer queue.deinit();
500
501 try queue.add(.{ .size = 54 });
502 try queue.add(.{ .size = 12 });
503 try queue.add(.{ .size = 7 });
504 try queue.add(.{ .size = 23 });
505 try queue.add(.{ .size = 25 });
506 try queue.add(.{ .size = 13 });
507
508 try expectEqual(@as(u32, 7), queue.removeMin().size);
509 try expectEqual(@as(u32, 12), queue.removeMin().size);
510 try expectEqual(@as(u32, 13), queue.removeMin().size);
511 try expectEqual(@as(u32, 23), queue.removeMin().size);
512 try expectEqual(@as(u32, 25), queue.removeMin().size);
513 try expectEqual(@as(u32, 54), queue.removeMin().size);
494 }.order).initContext({});
495 defer queue.deinit(gpa);
496
497 try queue.push(gpa, .{ .size = 54 });
498 try queue.push(gpa, .{ .size = 12 });
499 try queue.push(gpa, .{ .size = 7 });
500 try queue.push(gpa, .{ .size = 23 });
501 try queue.push(gpa, .{ .size = 25 });
502 try queue.push(gpa, .{ .size = 13 });
503
504 try expectEqual(@as(u32, 7), queue.popMin().?.size);
505 try expectEqual(@as(u32, 12), queue.popMin().?.size);
506 try expectEqual(@as(u32, 13), queue.popMin().?.size);
507 try expectEqual(@as(u32, 23), queue.popMin().?.size);
508 try expectEqual(@as(u32, 25), queue.popMin().?.size);
509 try expectEqual(@as(u32, 54), queue.popMin().?.size);
514510}
515511
516test "add and remove max" {
517 var queue = PDQ.init(testing.allocator, {});
518 defer queue.deinit();
519
520 try queue.add(54);
521 try queue.add(12);
522 try queue.add(7);
523 try queue.add(23);
524 try queue.add(25);
525 try queue.add(13);
526
527 try expectEqual(@as(u32, 54), queue.removeMax());
528 try expectEqual(@as(u32, 25), queue.removeMax());
529 try expectEqual(@as(u32, 23), queue.removeMax());
530 try expectEqual(@as(u32, 13), queue.removeMax());
531 try expectEqual(@as(u32, 12), queue.removeMax());
532 try expectEqual(@as(u32, 7), queue.removeMax());
512test "push and pop max in min heap" {
513 const gpa = std.testing.allocator;
514
515 var queue: MinHeap = .empty;
516 defer queue.deinit(gpa);
517
518 try queue.push(gpa, 54);
519 try queue.push(gpa, 12);
520 try queue.push(gpa, 7);
521 try queue.push(gpa, 23);
522 try queue.push(gpa, 25);
523 try queue.push(gpa, 13);
524
525 try expectEqual(@as(u32, 54), queue.popMax());
526 try expectEqual(@as(u32, 25), queue.popMax());
527 try expectEqual(@as(u32, 23), queue.popMax());
528 try expectEqual(@as(u32, 13), queue.popMax());
529 try expectEqual(@as(u32, 12), queue.popMax());
530 try expectEqual(@as(u32, 7), queue.popMax());
533531}
534532
535test "add and remove same min" {
536 var queue = PDQ.init(testing.allocator, {});
537 defer queue.deinit();
538
539 try queue.add(1);
540 try queue.add(1);
541 try queue.add(2);
542 try queue.add(2);
543 try queue.add(1);
544 try queue.add(1);
545
546 try expectEqual(@as(u32, 1), queue.removeMin());
547 try expectEqual(@as(u32, 1), queue.removeMin());
548 try expectEqual(@as(u32, 1), queue.removeMin());
549 try expectEqual(@as(u32, 1), queue.removeMin());
550 try expectEqual(@as(u32, 2), queue.removeMin());
551 try expectEqual(@as(u32, 2), queue.removeMin());
533test "push and pop same min in min heap" {
534 const gpa = std.testing.allocator;
535
536 var queue: MinHeap = .empty;
537 defer queue.deinit(gpa);
538
539 try queue.push(gpa, 1);
540 try queue.push(gpa, 1);
541 try queue.push(gpa, 2);
542 try queue.push(gpa, 2);
543 try queue.push(gpa, 1);
544 try queue.push(gpa, 1);
545
546 try expectEqual(@as(u32, 1), queue.popMin());
547 try expectEqual(@as(u32, 1), queue.popMin());
548 try expectEqual(@as(u32, 1), queue.popMin());
549 try expectEqual(@as(u32, 1), queue.popMin());
550 try expectEqual(@as(u32, 2), queue.popMin());
551 try expectEqual(@as(u32, 2), queue.popMin());
552552}
553553
554test "add and remove same max" {
555 var queue = PDQ.init(testing.allocator, {});
556 defer queue.deinit();
557
558 try queue.add(1);
559 try queue.add(1);
560 try queue.add(2);
561 try queue.add(2);
562 try queue.add(1);
563 try queue.add(1);
564
565 try expectEqual(@as(u32, 2), queue.removeMax());
566 try expectEqual(@as(u32, 2), queue.removeMax());
567 try expectEqual(@as(u32, 1), queue.removeMax());
568 try expectEqual(@as(u32, 1), queue.removeMax());
569 try expectEqual(@as(u32, 1), queue.removeMax());
570 try expectEqual(@as(u32, 1), queue.removeMax());
554test "push and pop same max in min heap" {
555 const gpa = std.testing.allocator;
556
557 var queue: MinHeap = .empty;
558 defer queue.deinit(gpa);
559
560 try queue.push(gpa, 1);
561 try queue.push(gpa, 1);
562 try queue.push(gpa, 2);
563 try queue.push(gpa, 2);
564 try queue.push(gpa, 1);
565 try queue.push(gpa, 1);
566
567 try expectEqual(@as(u32, 2), queue.popMax());
568 try expectEqual(@as(u32, 2), queue.popMax());
569 try expectEqual(@as(u32, 1), queue.popMax());
570 try expectEqual(@as(u32, 1), queue.popMax());
571 try expectEqual(@as(u32, 1), queue.popMax());
572 try expectEqual(@as(u32, 1), queue.popMax());
571573}
572574
573test "removeOrNull empty" {
574 var queue = PDQ.init(testing.allocator, {});
575 defer queue.deinit();
575test "pop empty in min heap" {
576 const gpa = std.testing.allocator;
577
578 var queue: MinHeap = .empty;
579 defer queue.deinit(gpa);
576580
577 try expect(queue.removeMinOrNull() == null);
578 try expect(queue.removeMaxOrNull() == null);
581 try expect(queue.popMin() == null);
582 try expect(queue.popMax() == null);
579583}
580584
581test "edge case 3 elements" {
582 var queue = PDQ.init(testing.allocator, {});
583 defer queue.deinit();
585test "edge case 3 elements popMin in min heap" {
586 const gpa = std.testing.allocator;
587
588 var queue: MinHeap = .empty;
589 defer queue.deinit(gpa);
584590
585 try queue.add(9);
586 try queue.add(3);
587 try queue.add(2);
591 try queue.push(gpa, 9);
592 try queue.push(gpa, 3);
593 try queue.push(gpa, 2);
588594
589 try expectEqual(@as(u32, 2), queue.removeMin());
590 try expectEqual(@as(u32, 3), queue.removeMin());
591 try expectEqual(@as(u32, 9), queue.removeMin());
595 try expectEqual(@as(u32, 2), queue.popMin());
596 try expectEqual(@as(u32, 3), queue.popMin());
597 try expectEqual(@as(u32, 9), queue.popMin());
592598}
593599
594test "edge case 3 elements max" {
595 var queue = PDQ.init(testing.allocator, {});
596 defer queue.deinit();
600test "edge case 3 elements popmax in min heap" {
601 const gpa = std.testing.allocator;
597602
598 try queue.add(9);
599 try queue.add(3);
600 try queue.add(2);
603 var queue: MinHeap = .empty;
604 defer queue.deinit(gpa);
601605
602 try expectEqual(@as(u32, 9), queue.removeMax());
603 try expectEqual(@as(u32, 3), queue.removeMax());
604 try expectEqual(@as(u32, 2), queue.removeMax());
606 try queue.push(gpa, 9);
607 try queue.push(gpa, 3);
608 try queue.push(gpa, 2);
609
610 try expectEqual(@as(u32, 9), queue.popMax());
611 try expectEqual(@as(u32, 3), queue.popMax());
612 try expectEqual(@as(u32, 2), queue.popMax());
605613}
606614
607test "peekMin" {
608 var queue = PDQ.init(testing.allocator, {});
609 defer queue.deinit();
615test "peekMin in min heap" {
616 const gpa = std.testing.allocator;
617
618 var queue: MinHeap = .empty;
619 defer queue.deinit(gpa);
610620
611621 try expect(queue.peekMin() == null);
612622
613 try queue.add(9);
614 try queue.add(3);
615 try queue.add(2);
623 try queue.push(gpa, 9);
624 try queue.push(gpa, 3);
625 try queue.push(gpa, 2);
616626
617627 try expect(queue.peekMin().? == 2);
618628 try expect(queue.peekMin().? == 2);
619629}
620630
621test "peekMax" {
622 var queue = PDQ.init(testing.allocator, {});
623 defer queue.deinit();
631test "peekMax in min heap" {
632 const gpa = std.testing.allocator;
633
634 var queue: MinHeap = .empty;
635 defer queue.deinit(gpa);
624636
625637 try expect(queue.peekMin() == null);
626638
627 try queue.add(9);
628 try queue.add(3);
629 try queue.add(2);
639 try queue.push(gpa, 9);
640 try queue.push(gpa, 3);
641 try queue.push(gpa, 2);
630642
631643 try expect(queue.peekMax().? == 9);
632644 try expect(queue.peekMax().? == 9);
633645}
634646
635test "sift up with odd indices, removeMin" {
636 var queue = PDQ.init(testing.allocator, {});
637 defer queue.deinit();
647test "sift up with odd indices and popMin in min heap" {
648 const gpa = std.testing.allocator;
649
650 var queue: MinHeap = .empty;
651 defer queue.deinit(gpa);
652
638653 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
639654 for (items) |e| {
640 try queue.add(e);
655 try queue.push(gpa, e);
641656 }
642657
643658 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
644659 for (sorted_items) |e| {
645 try expectEqual(e, queue.removeMin());
660 try expectEqual(e, queue.popMin());
646661 }
647662}
648663
649test "sift up with odd indices, removeMax" {
650 var queue = PDQ.init(testing.allocator, {});
651 defer queue.deinit();
664test "sift up with odd indices and popMax in min heap" {
665 const gpa = std.testing.allocator;
666
667 var queue: MinHeap = .empty;
668 defer queue.deinit(gpa);
669
652670 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
653671 for (items) |e| {
654 try queue.add(e);
672 try queue.push(gpa, e);
655673 }
656674
657675 const sorted_items = [_]u32{ 25, 24, 24, 22, 21, 16, 15, 15, 14, 13, 12, 11, 7, 7, 6, 5, 2, 1 };
658676 for (sorted_items) |e| {
659 try expectEqual(e, queue.removeMax());
677 try expectEqual(e, queue.popMax());
660678 }
661679}
662680
663test "addSlice min" {
664 var queue = PDQ.init(testing.allocator, {});
665 defer queue.deinit();
681test "pushSlice in min heap and popMin" {
682 const gpa = std.testing.allocator;
683
684 var queue: MinHeap = .empty;
685 defer queue.deinit(gpa);
686
666687 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
667 try queue.addSlice(items[0..]);
688 try queue.pushSlice(gpa, items[0..]);
668689
669690 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
670691 for (sorted_items) |e| {
671 try expectEqual(e, queue.removeMin());
692 try expectEqual(e, queue.popMin());
672693 }
673694}
674695
675test "addSlice max" {
676 var queue = PDQ.init(testing.allocator, {});
677 defer queue.deinit();
696test "pushSlice in min heap and popMax" {
697 const gpa = std.testing.allocator;
698
699 var queue: MinHeap = .empty;
700 defer queue.deinit(gpa);
701
678702 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
679 try queue.addSlice(items[0..]);
703 try queue.pushSlice(gpa, items[0..]);
680704
681705 const sorted_items = [_]u32{ 25, 24, 24, 22, 21, 16, 15, 15, 14, 13, 12, 11, 7, 7, 6, 5, 2, 1 };
682706 for (sorted_items) |e| {
683 try expectEqual(e, queue.removeMax());
707 try expectEqual(e, queue.popMax());
684708 }
685709}
686710
687test "fromOwnedSlice trivial case 0" {
711test "fromOwnedSlice trivial case 0 min heap" {
712 const gpa = std.testing.allocator;
713
688714 const items = [0]u32{};
689 const queue_items = try testing.allocator.dupe(u32, &items);
690 var queue = PDQ.fromOwnedSlice(testing.allocator, queue_items[0..], {});
691 defer queue.deinit();
715 const queue_items = try gpa.dupe(u32, &items);
716
717 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
718 defer queue.deinit(gpa);
719
692720 try expectEqual(@as(usize, 0), queue.len);
693 try expect(queue.removeMinOrNull() == null);
721 try expect(queue.popMin() == null);
694722}
695723
696test "fromOwnedSlice trivial case 1" {
724test "fromOwnedSlice trivial case 1 min heap" {
725 const gpa = std.testing.allocator;
726
697727 const items = [1]u32{1};
698 const queue_items = try testing.allocator.dupe(u32, &items);
699 var queue = PDQ.fromOwnedSlice(testing.allocator, queue_items[0..], {});
700 defer queue.deinit();
728 const queue_items = try gpa.dupe(u32, &items);
729
730 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
731 defer queue.deinit(gpa);
701732
702733 try expectEqual(@as(usize, 1), queue.len);
703 try expectEqual(items[0], queue.removeMin());
704 try expect(queue.removeMinOrNull() == null);
734 try expectEqual(items[0], queue.popMin());
735 try expect(queue.popMin() == null);
705736}
706737
707test "fromOwnedSlice" {
738test "fromOwnedSlice min heap" {
739 const gpa = std.testing.allocator;
740
708741 const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
709 const queue_items = try testing.allocator.dupe(u32, items[0..]);
710 var queue = PDQ.fromOwnedSlice(testing.allocator, queue_items[0..], {});
711 defer queue.deinit();
742 const queue_items = try gpa.dupe(u32, items[0..]);
743
744 var queue: MinHeap = .fromOwnedSlice(queue_items[0..], {});
745 defer queue.deinit(gpa);
712746
713747 const sorted_items = [_]u32{ 1, 2, 5, 6, 7, 7, 11, 12, 13, 14, 15, 15, 16, 21, 22, 24, 24, 25 };
714748 for (sorted_items) |e| {
715 try expectEqual(e, queue.removeMin());
749 try expectEqual(e, queue.popMin());
716750 }
717751}
718752
719test "update min queue" {
720 var queue = PDQ.init(testing.allocator, {});
721 defer queue.deinit();
753test "update and popMin in min heap" {
754 const gpa = std.testing.allocator;
722755
723 try queue.add(55);
724 try queue.add(44);
725 try queue.add(11);
756 var queue: MinHeap = .empty;
757 defer queue.deinit(gpa);
758
759 try queue.push(gpa, 55);
760 try queue.push(gpa, 44);
761 try queue.push(gpa, 11);
726762 try queue.update(55, 5);
727763 try queue.update(44, 4);
728764 try queue.update(11, 1);
729 try expectEqual(@as(u32, 1), queue.removeMin());
730 try expectEqual(@as(u32, 4), queue.removeMin());
731 try expectEqual(@as(u32, 5), queue.removeMin());
765 try expectEqual(@as(u32, 1), queue.popMin());
766 try expectEqual(@as(u32, 4), queue.popMin());
767 try expectEqual(@as(u32, 5), queue.popMin());
732768}
733769
734test "update same min queue" {
735 var queue = PDQ.init(testing.allocator, {});
736 defer queue.deinit();
770test "update same element and popMin in min heap" {
771 const gpa = std.testing.allocator;
772
773 var queue: MinHeap = .empty;
774 defer queue.deinit(gpa);
737775
738 try queue.add(1);
739 try queue.add(1);
740 try queue.add(2);
741 try queue.add(2);
776 try queue.push(gpa, 1);
777 try queue.push(gpa, 1);
778 try queue.push(gpa, 2);
779 try queue.push(gpa, 2);
742780 try queue.update(1, 5);
743781 try queue.update(2, 4);
744 try expectEqual(@as(u32, 1), queue.removeMin());
745 try expectEqual(@as(u32, 2), queue.removeMin());
746 try expectEqual(@as(u32, 4), queue.removeMin());
747 try expectEqual(@as(u32, 5), queue.removeMin());
782 try expectEqual(@as(u32, 1), queue.popMin());
783 try expectEqual(@as(u32, 2), queue.popMin());
784 try expectEqual(@as(u32, 4), queue.popMin());
785 try expectEqual(@as(u32, 5), queue.popMin());
748786}
749787
750test "update max queue" {
751 var queue = PDQ.init(testing.allocator, {});
752 defer queue.deinit();
788test "update and popMax in min heap" {
789 const gpa = std.testing.allocator;
790
791 var queue: MinHeap = .empty;
792 defer queue.deinit(gpa);
753793
754 try queue.add(55);
755 try queue.add(44);
756 try queue.add(11);
794 try queue.push(gpa, 55);
795 try queue.push(gpa, 44);
796 try queue.push(gpa, 11);
757797 try queue.update(55, 5);
758798 try queue.update(44, 1);
759799 try queue.update(11, 4);
760800
761 try expectEqual(@as(u32, 5), queue.removeMax());
762 try expectEqual(@as(u32, 4), queue.removeMax());
763 try expectEqual(@as(u32, 1), queue.removeMax());
801 try expectEqual(@as(u32, 5), queue.popMax());
802 try expectEqual(@as(u32, 4), queue.popMax());
803 try expectEqual(@as(u32, 1), queue.popMax());
764804}
765805
766test "update same max queue" {
767 var queue = PDQ.init(testing.allocator, {});
768 defer queue.deinit();
806test "update same element and popMax in min heap" {
807 const gpa = std.testing.allocator;
769808
770 try queue.add(1);
771 try queue.add(1);
772 try queue.add(2);
773 try queue.add(2);
809 var queue: MinHeap = .empty;
810 defer queue.deinit(gpa);
811
812 try queue.push(gpa, 1);
813 try queue.push(gpa, 1);
814 try queue.push(gpa, 2);
815 try queue.push(gpa, 2);
774816 try queue.update(1, 5);
775817 try queue.update(2, 4);
776 try expectEqual(@as(u32, 5), queue.removeMax());
777 try expectEqual(@as(u32, 4), queue.removeMax());
778 try expectEqual(@as(u32, 2), queue.removeMax());
779 try expectEqual(@as(u32, 1), queue.removeMax());
818 try expectEqual(@as(u32, 5), queue.popMax());
819 try expectEqual(@as(u32, 4), queue.popMax());
820 try expectEqual(@as(u32, 2), queue.popMax());
821 try expectEqual(@as(u32, 1), queue.popMax());
780822}
781823
782test "update after remove" {
783 var queue = PDQ.init(testing.allocator, {});
784 defer queue.deinit();
824test "update after pop in min heap" {
825 const gpa = std.testing.allocator;
826
827 var queue: MinHeap = .empty;
828 defer queue.deinit(gpa);
785829
786 try queue.add(1);
787 try expectEqual(@as(u32, 1), queue.removeMin());
830 try queue.push(gpa, 1);
831 try expectEqual(@as(u32, 1), queue.popMin());
788832 try expectError(error.ElementNotFound, queue.update(1, 1));
789833}
790834
791test "iterator" {
792 var queue = PDQ.init(testing.allocator, {});
835test "min heap iterator" {
836 const gpa = std.testing.allocator;
837
838 var queue: MinHeap = .empty;
793839 var map = std.AutoHashMap(u32, void).init(testing.allocator);
794840 defer {
795 queue.deinit();
841 queue.deinit(gpa);
796842 map.deinit();
797843 }
798844
799845 const items = [_]u32{ 54, 12, 7, 23, 25, 13 };
800846 for (items) |e| {
801 _ = try queue.add(e);
847 _ = try queue.push(gpa, e);
802848 _ = try map.put(e, {});
803849 }
804850
......@@ -810,13 +856,15 @@ test "iterator" {
810856 try expectEqual(@as(usize, 0), map.count());
811857}
812858
813test "remove at index" {
814 var queue = PDQ.init(testing.allocator, {});
815 defer queue.deinit();
859test "pop at index in min heap" {
860 const gpa = std.testing.allocator;
816861
817 try queue.add(3);
818 try queue.add(2);
819 try queue.add(1);
862 var queue: MinHeap = .empty;
863 defer queue.deinit(gpa);
864
865 try queue.push(gpa, 3);
866 try queue.push(gpa, 2);
867 try queue.push(gpa, 1);
820868
821869 var it = queue.iterator();
822870 var elem = it.next();
......@@ -827,42 +875,46 @@ test "remove at index" {
827875 idx += 1;
828876 } else unreachable;
829877
830 try expectEqual(queue.removeIndex(two_idx), 2);
831 try expectEqual(queue.removeMin(), 1);
832 try expectEqual(queue.removeMin(), 3);
833 try expectEqual(queue.removeMinOrNull(), null);
878 try expectEqual(queue.popIndex(two_idx), 2);
879 try expectEqual(queue.popMin(), 1);
880 try expectEqual(queue.popMin(), 3);
881 try expectEqual(queue.popMin(), null);
834882}
835883
836test "iterator while empty" {
837 var queue = PDQ.init(testing.allocator, {});
838 defer queue.deinit();
884test "min heap iterator while empty" {
885 const gpa = std.testing.allocator;
886
887 var queue: MinHeap = .empty;
888 defer queue.deinit(gpa);
839889
840890 var it = queue.iterator();
841891
842892 try expectEqual(it.next(), null);
843893}
844894
845test "shrinkAndFree" {
846 var queue = PDQ.init(testing.allocator, {});
847 defer queue.deinit();
895test "min heap shrinkAndFree" {
896 const gpa = std.testing.allocator;
897
898 var queue: MinHeap = .empty;
899 defer queue.deinit(gpa);
848900
849 try queue.ensureTotalCapacity(4);
901 try queue.ensureTotalCapacity(gpa, 4);
850902 try expect(queue.capacity() >= 4);
851903
852 try queue.add(1);
853 try queue.add(2);
854 try queue.add(3);
904 try queue.push(gpa, 1);
905 try queue.push(gpa, 2);
906 try queue.push(gpa, 3);
855907 try expect(queue.capacity() >= 4);
856908 try expectEqual(@as(usize, 3), queue.len);
857909
858 queue.shrinkAndFree(3);
910 queue.shrinkAndFree(gpa, 3);
859911 try expectEqual(@as(usize, 3), queue.capacity());
860912 try expectEqual(@as(usize, 3), queue.len);
861913
862 try expectEqual(@as(u32, 3), queue.removeMax());
863 try expectEqual(@as(u32, 2), queue.removeMax());
864 try expectEqual(@as(u32, 1), queue.removeMax());
865 try expect(queue.removeMaxOrNull() == null);
914 try expectEqual(@as(u32, 3), queue.popMax());
915 try expectEqual(@as(u32, 2), queue.popMax());
916 try expectEqual(@as(u32, 1), queue.popMax());
917 try expect(queue.popMax() == null);
866918}
867919
868920test "fuzz testing min" {
......@@ -879,14 +931,15 @@ test "fuzz testing min" {
879931}
880932
881933fn fuzzTestMin(rng: std.Random, comptime queue_size: usize) !void {
882 const allocator = testing.allocator;
883 const items = try generateRandomSlice(allocator, rng, queue_size);
934 const gpa = std.testing.allocator;
884935
885 var queue = PDQ.fromOwnedSlice(allocator, items, {});
886 defer queue.deinit();
936 const items = try generateRandomSlice(gpa, rng, queue_size);
937
938 var queue: MinHeap = .fromOwnedSlice(items, {});
939 defer queue.deinit(gpa);
887940
888941 var last_removed: ?u32 = null;
889 while (queue.removeMinOrNull()) |next| {
942 while (queue.popMin()) |next| {
890943 if (last_removed) |last| {
891944 try expect(last <= next);
892945 }
......@@ -908,14 +961,15 @@ test "fuzz testing max" {
908961}
909962
910963fn fuzzTestMax(rng: std.Random, queue_size: usize) !void {
911 const allocator = testing.allocator;
912 const items = try generateRandomSlice(allocator, rng, queue_size);
964 const gpa = std.testing.allocator;
965
966 const items = try generateRandomSlice(gpa, rng, queue_size);
913967
914 var queue = PDQ.fromOwnedSlice(testing.allocator, items, {});
915 defer queue.deinit();
968 var queue: MinHeap = .fromOwnedSlice(items, {});
969 defer queue.deinit(gpa);
916970
917971 var last_removed: ?u32 = null;
918 while (queue.removeMaxOrNull()) |next| {
972 while (queue.popMax()) |next| {
919973 if (last_removed) |last| {
920974 try expect(last >= next);
921975 }
......@@ -937,24 +991,25 @@ test "fuzz testing min and max" {
937991}
938992
939993fn fuzzTestMinMax(rng: std.Random, queue_size: usize) !void {
940 const allocator = testing.allocator;
941 const items = try generateRandomSlice(allocator, rng, queue_size);
994 const gpa = std.testing.allocator;
995
996 const items = try generateRandomSlice(gpa, rng, queue_size);
942997
943 var queue = PDQ.fromOwnedSlice(allocator, items, {});
944 defer queue.deinit();
998 var queue: MinHeap = .fromOwnedSlice(items, {});
999 defer queue.deinit(gpa);
9451000
9461001 var last_min: ?u32 = null;
9471002 var last_max: ?u32 = null;
9481003 var i: usize = 0;
9491004 while (i < queue_size) : (i += 1) {
9501005 if (i % 2 == 0) {
951 const next = queue.removeMin();
1006 const next = queue.popMin().?;
9521007 if (last_min) |last| {
9531008 try expect(last <= next);
9541009 }
9551010 last_min = next;
9561011 } else {
957 const next = queue.removeMax();
1012 const next = queue.popMax().?;
9581013 if (last_max) |last| {
9591014 try expect(last >= next);
9601015 }
......@@ -980,48 +1035,52 @@ fn contextLessThanComparison(context: []const u32, a: usize, b: usize) Order {
9801035 return std.math.order(context[a], context[b]);
9811036}
9821037
983const CPDQ = PriorityDequeue(usize, []const u32, contextLessThanComparison);
1038const MinHeapWithContext = PriorityDequeue(usize, []const u32, contextLessThanComparison);
1039
1040test "push and pop" {
1041 const gpa = std.testing.allocator;
9841042
985test "add and remove" {
9861043 const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };
9871044
988 var queue = CPDQ.init(testing.allocator, context[0..]);
989 defer queue.deinit();
990
991 try queue.add(0);
992 try queue.add(1);
993 try queue.add(2);
994 try queue.add(3);
995 try queue.add(4);
996 try queue.add(5);
997 try queue.add(6);
998 try expectEqual(@as(usize, 6), queue.removeMin());
999 try expectEqual(@as(usize, 5), queue.removeMax());
1000 try expectEqual(@as(usize, 3), queue.removeMin());
1001 try expectEqual(@as(usize, 0), queue.removeMax());
1002 try expectEqual(@as(usize, 4), queue.removeMin());
1003 try expectEqual(@as(usize, 2), queue.removeMax());
1004 try expectEqual(@as(usize, 1), queue.removeMin());
1045 var queue: MinHeapWithContext = .initContext(context[0..]);
1046 defer queue.deinit(gpa);
1047
1048 try queue.push(gpa, 0);
1049 try queue.push(gpa, 1);
1050 try queue.push(gpa, 2);
1051 try queue.push(gpa, 3);
1052 try queue.push(gpa, 4);
1053 try queue.push(gpa, 5);
1054 try queue.push(gpa, 6);
1055 try expectEqual(@as(usize, 6), queue.popMin());
1056 try expectEqual(@as(usize, 5), queue.popMax());
1057 try expectEqual(@as(usize, 3), queue.popMin());
1058 try expectEqual(@as(usize, 0), queue.popMax());
1059 try expectEqual(@as(usize, 4), queue.popMin());
1060 try expectEqual(@as(usize, 2), queue.popMax());
1061 try expectEqual(@as(usize, 1), queue.popMin());
10051062}
10061063
10071064var all_cmps_unique = true;
10081065
10091066test "don't compare a value to a copy of itself" {
1067 const gpa = std.testing.allocator;
1068
10101069 var depq = PriorityDequeue(u32, void, struct {
10111070 fn uniqueLessThan(_: void, a: u32, b: u32) Order {
10121071 all_cmps_unique = all_cmps_unique and (a != b);
10131072 return std.math.order(a, b);
10141073 }
1015 }.uniqueLessThan).init(testing.allocator, {});
1016 defer depq.deinit();
1074 }.uniqueLessThan).initContext({});
1075 defer depq.deinit(gpa);
10171076
1018 try depq.add(1);
1019 try depq.add(2);
1020 try depq.add(3);
1021 try depq.add(4);
1022 try depq.add(5);
1023 try depq.add(6);
1077 try depq.push(gpa, 1);
1078 try depq.push(gpa, 2);
1079 try depq.push(gpa, 3);
1080 try depq.push(gpa, 4);
1081 try depq.push(gpa, 5);
1082 try depq.push(gpa, 6);
10241083
1025 _ = depq.removeIndex(2);
1084 _ = depq.popIndex(2);
10261085 try expectEqual(all_cmps_unique, true);
10271086}