From 369e44a8186a6661dbad027c5f170b109b75e553 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sat, 29 Nov 2025 17:15:31 +0530 Subject: [PATCH 01/13] init --- .../alloc/src/collections/binary_heap/mod.rs | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 63828b482b9a9..ce0d9375c2735 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -776,7 +776,11 @@ impl BinaryHeap { unsafe fn sift_down_range(&mut self, pos: usize, end: usize) -> usize { // SAFETY: The caller guarantees that pos < end <= self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - let mut child = 2 * hole.pos() + 1; + // Guarded computation of left child: 2 * hole.pos() + 1. On overflow, no children exist. + let mut child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { + Some(idx) => idx, + None => return hole.pos(), + }; // Loop invariant: child == 2 * hole.pos() + 1. while child <= end.saturating_sub(2) { @@ -785,8 +789,6 @@ impl BinaryHeap { // child + 1 < end <= self.len(), so they're valid indexes. // child == 2 * hole.pos() + 1 != hole.pos() and // child + 1 == 2 * hole.pos() + 2 != hole.pos(). - // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow - // if T is a ZST child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize; // if we are already in order, stop. @@ -798,7 +800,11 @@ impl BinaryHeap { // SAFETY: same as above. unsafe { hole.move_to(child) }; - child = 2 * hole.pos() + 1; + // Recompute guarded left child for new hole position. + child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { + Some(idx) => idx, + None => return hole.pos(), + }; } // SAFETY: && short circuit, which means that in the @@ -837,7 +843,16 @@ impl BinaryHeap { // SAFETY: The caller guarantees that pos < self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - let mut child = 2 * hole.pos() + 1; + let mut child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { + Some(idx) => idx, + None => { + let pos = hole.pos(); + // Drop the hole to release the &mut borrow of self.data before reborrowing self. + drop(hole); + unsafe { self.sift_up(start, pos) }; + return; + } + }; // Loop invariant: child == 2 * hole.pos() + 1. while child <= end.saturating_sub(2) { @@ -845,13 +860,15 @@ impl BinaryHeap { // child + 1 < end <= self.len(), so they're valid indexes. // child == 2 * hole.pos() + 1 != hole.pos() and // child + 1 == 2 * hole.pos() + 2 != hole.pos(). - // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow - // if T is a ZST child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize; // SAFETY: Same as above unsafe { hole.move_to(child) }; - child = 2 * hole.pos() + 1; + + child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { + Some(idx) => idx, + None => break, // No further children; exit loop. + }; } if child == end - 1 { From c023aba47940b34592ee3ecaa9919f3c5217f576 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 14:32:00 +0530 Subject: [PATCH 02/13] try updating sift down range first --- .../alloc/src/collections/binary_heap/mod.rs | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index ce0d9375c2735..dcfdc4158ccd1 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -776,14 +776,16 @@ impl BinaryHeap { unsafe fn sift_down_range(&mut self, pos: usize, end: usize) -> usize { // SAFETY: The caller guarantees that pos < end <= self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - // Guarded computation of left child: 2 * hole.pos() + 1. On overflow, no children exist. - let mut child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { - Some(idx) => idx, - None => return hole.pos(), - }; + let mut child = hole.pos(); // Loop invariant: child == 2 * hole.pos() + 1. - while child <= end.saturating_sub(2) { + while hole.pos <= end.saturating_sub(2) / 2 { + // Using the invariant, we can see + // hole <= (end - 2) / 2 + // => (child - 1) / 2 <= (end - 2) / 2 + // => child <= end - 1, which is guaranteed by caller + child = 2 * hole.pos() + 1; + // compare with the greater of the two children // SAFETY: child < end - 1 < self.len() and // child + 1 < end <= self.len(), so they're valid indexes. @@ -800,19 +802,6 @@ impl BinaryHeap { // SAFETY: same as above. unsafe { hole.move_to(child) }; - // Recompute guarded left child for new hole position. - child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { - Some(idx) => idx, - None => return hole.pos(), - }; - } - - // SAFETY: && short circuit, which means that in the - // second condition it's already true that child == end - 1 < self.len(). - if child == end - 1 && hole.element() < unsafe { hole.get(child) } { - // SAFETY: child is already proven to be a valid index and - // child == 2 * hole.pos() + 1 != hole.pos(). - unsafe { hole.move_to(child) }; } hole.pos() @@ -843,16 +832,7 @@ impl BinaryHeap { // SAFETY: The caller guarantees that pos < self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - let mut child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { - Some(idx) => idx, - None => { - let pos = hole.pos(); - // Drop the hole to release the &mut borrow of self.data before reborrowing self. - drop(hole); - unsafe { self.sift_up(start, pos) }; - return; - } - }; + let mut child = 2 * hole.pos() + 1; // Loop invariant: child == 2 * hole.pos() + 1. while child <= end.saturating_sub(2) { @@ -860,15 +840,13 @@ impl BinaryHeap { // child + 1 < end <= self.len(), so they're valid indexes. // child == 2 * hole.pos() + 1 != hole.pos() and // child + 1 == 2 * hole.pos() + 2 != hole.pos(). + // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow + // if T is a ZST child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize; // SAFETY: Same as above unsafe { hole.move_to(child) }; - - child = match hole.pos().checked_mul(2).and_then(|x| x.checked_add(1)) { - Some(idx) => idx, - None => break, // No further children; exit loop. - }; + child = 2 * hole.pos() + 1; } if child == end - 1 { From 3741d95a41e93e8ba3274a7cafa0a3b9ab9c23ca Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 14:38:44 +0530 Subject: [PATCH 03/13] unused var fix --- library/alloc/src/collections/binary_heap/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index dcfdc4158ccd1..a36e0985dbd7b 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -776,15 +776,14 @@ impl BinaryHeap { unsafe fn sift_down_range(&mut self, pos: usize, end: usize) -> usize { // SAFETY: The caller guarantees that pos < end <= self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - let mut child = hole.pos(); // Loop invariant: child == 2 * hole.pos() + 1. - while hole.pos <= end.saturating_sub(2) / 2 { + while hole.pos() <= end.saturating_sub(2) / 2 { // Using the invariant, we can see // hole <= (end - 2) / 2 // => (child - 1) / 2 <= (end - 2) / 2 // => child <= end - 1, which is guaranteed by caller - child = 2 * hole.pos() + 1; + let mut child = 2 * hole.pos() + 1; // compare with the greater of the two children // SAFETY: child < end - 1 < self.len() and From 988fda41291f9e1f54b9cd161556a3f958322992 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 15:05:47 +0530 Subject: [PATCH 04/13] fix for single child --- .../alloc/src/collections/binary_heap/mod.rs | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index a36e0985dbd7b..cb0a8ad58b406 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -778,11 +778,12 @@ impl BinaryHeap { let mut hole = unsafe { Hole::new(&mut self.data, pos) }; // Loop invariant: child == 2 * hole.pos() + 1. - while hole.pos() <= end.saturating_sub(2) / 2 { - // Using the invariant, we can see - // hole <= (end - 2) / 2 - // => (child - 1) / 2 <= (end - 2) / 2 - // => child <= end - 1, which is guaranteed by caller + // + // The condition makes sure that hole will have atleat two children + // child + 1 <= end - 1 + // => 2 * hole + 2 <= end - 1 + // => hole <= (end - 3) / 2 + while hole.pos() <= end.saturating_sub(3) / 2 { let mut child = 2 * hole.pos() + 1; // compare with the greater of the two children @@ -803,6 +804,19 @@ impl BinaryHeap { unsafe { hole.move_to(child) }; } + // If hole has only one child + // child <= end - 1 + // => 2 * hole + 1 <= end - 1 + // => hole <= (end - 2) / 2 + if hole.pos() <= end.saturating_sub(2) / 2 { + let child = 2 * hole.pos() + 1; + // Case where the only child is greater/less than hole + if hole.element() < unsafe { hole.get(child) } { + unsafe { hole.move_to(child) }; + } + } + + // Otherwise return the same position hole.pos() } From 0fd9c20d8e7b2aebcd0346b5e2e98cd52c75b740 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 15:14:12 +0530 Subject: [PATCH 05/13] Fix explanation --- library/alloc/src/collections/binary_heap/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index cb0a8ad58b406..e34de7f8b1803 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -779,7 +779,7 @@ impl BinaryHeap { // Loop invariant: child == 2 * hole.pos() + 1. // - // The condition makes sure that hole will have atleat two children + // The condition makes sure that hole will have atleast two children: // child + 1 <= end - 1 // => 2 * hole + 2 <= end - 1 // => hole <= (end - 3) / 2 @@ -804,13 +804,13 @@ impl BinaryHeap { unsafe { hole.move_to(child) }; } - // If hole has only one child + // If the parent has only one child: // child <= end - 1 // => 2 * hole + 1 <= end - 1 // => hole <= (end - 2) / 2 if hole.pos() <= end.saturating_sub(2) / 2 { let child = 2 * hole.pos() + 1; - // Case where the only child is greater/less than hole + // If we are not in order, move parent if hole.element() < unsafe { hole.get(child) } { unsafe { hole.move_to(child) }; } From 14073acb0c0ade67fbd6250307f120339a2d34a5 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 16:05:25 +0530 Subject: [PATCH 06/13] fixed tests panic --- library/alloc/src/collections/binary_heap/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index e34de7f8b1803..8a2a5a04a95b9 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -783,7 +783,7 @@ impl BinaryHeap { // child + 1 <= end - 1 // => 2 * hole + 2 <= end - 1 // => hole <= (end - 3) / 2 - while hole.pos() <= end.saturating_sub(3) / 2 { + while end >= 3 && hole.pos() <= (end - 3) / 2 { let mut child = 2 * hole.pos() + 1; // compare with the greater of the two children @@ -808,7 +808,7 @@ impl BinaryHeap { // child <= end - 1 // => 2 * hole + 1 <= end - 1 // => hole <= (end - 2) / 2 - if hole.pos() <= end.saturating_sub(2) / 2 { + if end >= 2 && hole.pos() <= (end - 2) / 2 { let child = 2 * hole.pos() + 1; // If we are not in order, move parent if hole.element() < unsafe { hole.get(child) } { From a77d147a5fec731ee67ab13e4a21c508e6deb879 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 17:55:16 +0530 Subject: [PATCH 07/13] simplify loop conditions for sift_down_range --- .../alloc/src/collections/binary_heap/mod.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 8a2a5a04a95b9..ddc4c6bbe3e87 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -779,11 +779,13 @@ impl BinaryHeap { // Loop invariant: child == 2 * hole.pos() + 1. // - // The condition makes sure that hole will have atleast two children: - // child + 1 <= end - 1 - // => 2 * hole + 2 <= end - 1 + // While hole's position is below parent of the first empty slot + // child + 1 <= end - 1 (The second child is max at the first empty slot) + // => 2 * hole + 2 <= end - 1 ( From the invariant) // => hole <= (end - 3) / 2 - while end >= 3 && hole.pos() <= (end - 3) / 2 { + // => hole < 1 + (end - 3) / 2 + // => hole < (end - 1) / 2 + while hole.pos() < (end - 1) / 2 { let mut child = 2 * hole.pos() + 1; // compare with the greater of the two children @@ -804,11 +806,14 @@ impl BinaryHeap { unsafe { hole.move_to(child) }; } - // If the parent has only one child: + // If hole has only one child. + // // child <= end - 1 - // => 2 * hole + 1 <= end - 1 + // => 2 * hole + 1 <= end - 1 // => hole <= (end - 2) / 2 - if end >= 2 && hole.pos() <= (end - 2) / 2 { + // => hole < 1 + (end - 2) / 2 + // => hole < end / 2 + if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; // If we are not in order, move parent if hole.element() < unsafe { hole.get(child) } { From fc7af01d03d769713a99b46ec155d2a55678da35 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 18:02:01 +0530 Subject: [PATCH 08/13] updated sift_down_to_bottom also --- .../alloc/src/collections/binary_heap/mod.rs | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index ddc4c6bbe3e87..34f3223789ef0 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -850,27 +850,41 @@ impl BinaryHeap { // SAFETY: The caller guarantees that pos < self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - let mut child = 2 * hole.pos() + 1; // Loop invariant: child == 2 * hole.pos() + 1. - while child <= end.saturating_sub(2) { + // + // While hole's position is below parent of the first empty slot + // child + 1 <= end - 1 (The second child is max at the first empty slot) + // => 2 * hole + 2 <= end - 1 ( From the invariant) + // => hole <= (end - 3) / 2 + // => hole < 1 + (end - 3) / 2 + // => hole < (end - 1) / 2 + while hole.pos() < (end - 1) / 2 { + let mut child = 2 * hole.pos() + 1; + // SAFETY: child < end - 1 < self.len() and // child + 1 < end <= self.len(), so they're valid indexes. // child == 2 * hole.pos() + 1 != hole.pos() and // child + 1 == 2 * hole.pos() + 2 != hole.pos(). - // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow - // if T is a ZST child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize; // SAFETY: Same as above unsafe { hole.move_to(child) }; - child = 2 * hole.pos() + 1; } - if child == end - 1 { - // SAFETY: child == end - 1 < self.len(), so it's a valid index - // and child == 2 * hole.pos() + 1 != hole.pos(). - unsafe { hole.move_to(child) }; + // If hole has only one child. + // + // child <= end - 1 + // => 2 * hole + 1 <= end - 1 + // => hole <= (end - 2) / 2 + // => hole < 1 + (end - 2) / 2 + // => hole < end / 2 + if hole.pos() < end / 2 { + let child = 2 * hole.pos() + 1; + // If we are not in order, move parent + if hole.element() < unsafe { hole.get(child) } { + unsafe { hole.move_to(child) }; + } } pos = hole.pos(); drop(hole); From d07fbdb6619b5644bd27ddeb5085fd805227fe9f Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 19:46:39 +0530 Subject: [PATCH 09/13] applied pr suggestions --- .../alloc/src/collections/binary_heap/mod.rs | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 34f3223789ef0..dd2ab7a22cd15 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -777,14 +777,7 @@ impl BinaryHeap { // SAFETY: The caller guarantees that pos < end <= self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - // Loop invariant: child == 2 * hole.pos() + 1. - // // While hole's position is below parent of the first empty slot - // child + 1 <= end - 1 (The second child is max at the first empty slot) - // => 2 * hole + 2 <= end - 1 ( From the invariant) - // => hole <= (end - 3) / 2 - // => hole < 1 + (end - 3) / 2 - // => hole < (end - 1) / 2 while hole.pos() < (end - 1) / 2 { let mut child = 2 * hole.pos() + 1; @@ -808,15 +801,21 @@ impl BinaryHeap { // If hole has only one child. // - // child <= end - 1 - // => 2 * hole + 1 <= end - 1 - // => hole <= (end - 2) / 2 - // => hole < 1 + (end - 2) / 2 + // We want: child < end + // => 2 * hole + 1 < end + // => hole < (end - 1) / 2 + // + // For integers this is same as: // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; - // If we are not in order, move parent + // If elements are not in order, move parent + // + // SAFETY: The previous statements imply + // child is a valid index (child < end <= self.len()), + // and child != hole.pos(). if hole.element() < unsafe { hole.get(child) } { + // SAFETY: same as above unsafe { hole.move_to(child) }; } } @@ -851,14 +850,7 @@ impl BinaryHeap { // SAFETY: The caller guarantees that pos < self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; - // Loop invariant: child == 2 * hole.pos() + 1. - // // While hole's position is below parent of the first empty slot - // child + 1 <= end - 1 (The second child is max at the first empty slot) - // => 2 * hole + 2 <= end - 1 ( From the invariant) - // => hole <= (end - 3) / 2 - // => hole < 1 + (end - 3) / 2 - // => hole < (end - 1) / 2 while hole.pos() < (end - 1) / 2 { let mut child = 2 * hole.pos() + 1; @@ -874,15 +866,21 @@ impl BinaryHeap { // If hole has only one child. // - // child <= end - 1 - // => 2 * hole + 1 <= end - 1 - // => hole <= (end - 2) / 2 - // => hole < 1 + (end - 2) / 2 + // We want: child < end + // => 2 * hole + 1 < end + // => hole < (end - 1) / 2 + // + // For integers this is same as: // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; - // If we are not in order, move parent + // If elements are not in order, move parent + // + // SAFETY: The previous statements imply + // child is a valid index (child < end <= self.len()), + // and child != hole.pos(). if hole.element() < unsafe { hole.get(child) } { + // SAFETY: same as above unsafe { hole.move_to(child) }; } } From d6464a62c92d3a761e73406c65f9be7a19a97b29 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 19:59:58 +0530 Subject: [PATCH 10/13] fixed mistake in code explanation --- library/alloc/src/collections/binary_heap/mod.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index dd2ab7a22cd15..2a0e2ce3a8507 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -801,11 +801,9 @@ impl BinaryHeap { // If hole has only one child. // - // We want: child < end - // => 2 * hole + 1 < end - // => hole < (end - 1) / 2 - // - // For integers this is same as: + // We want: child <= end + // => 2 * hole + 1 <= end + // => 2 * hole + 1 < end + 1 // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; @@ -866,11 +864,9 @@ impl BinaryHeap { // If hole has only one child. // - // We want: child < end - // => 2 * hole + 1 < end - // => hole < (end - 1) / 2 - // - // For integers this is same as: + // We want: child <= end + // => 2 * hole + 1 <= end + // => 2 * hole + 1 < end + 1 // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; From 1a34f0a61dc81546385233e759e7315159ef9bed Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 20:02:10 +0530 Subject: [PATCH 11/13] fix again ;-; --- library/alloc/src/collections/binary_heap/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 2a0e2ce3a8507..45fb556642322 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -801,9 +801,10 @@ impl BinaryHeap { // If hole has only one child. // - // We want: child <= end - // => 2 * hole + 1 <= end - // => 2 * hole + 1 < end + 1 + // We want: child <= end - 1 + // => 2 * hole + 1 <= end - 1 + // => hole <= (end - 2) / 2 + // => hole < 1 + (end - 2) / 2 // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; @@ -864,9 +865,10 @@ impl BinaryHeap { // If hole has only one child. // - // We want: child <= end - // => 2 * hole + 1 <= end - // => 2 * hole + 1 < end + 1 + // We want: child <= end - 1 + // => 2 * hole + 1 <= end - 1 + // => hole <= (end - 2) / 2 + // => hole < 1 + (end - 2) / 2 // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; From e19d30a8426b26170e67fd3da550b87e02243e89 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Sun, 30 Nov 2025 22:51:48 +0530 Subject: [PATCH 12/13] cleaned single child case --- .../alloc/src/collections/binary_heap/mod.rs | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 45fb556642322..0245437aae297 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -800,19 +800,14 @@ impl BinaryHeap { } // If hole has only one child. - // - // We want: child <= end - 1 - // => 2 * hole + 1 <= end - 1 - // => hole <= (end - 2) / 2 - // => hole < 1 + (end - 2) / 2 - // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; + debug_assert!(child == end - 1); + // If elements are not in order, move parent - // // SAFETY: The previous statements imply - // child is a valid index (child < end <= self.len()), - // and child != hole.pos(). + // child is a valid index (child < end <= self.len()), + // and child != hole.pos(). if hole.element() < unsafe { hole.get(child) } { // SAFETY: same as above unsafe { hole.move_to(child) }; @@ -864,19 +859,14 @@ impl BinaryHeap { } // If hole has only one child. - // - // We want: child <= end - 1 - // => 2 * hole + 1 <= end - 1 - // => hole <= (end - 2) / 2 - // => hole < 1 + (end - 2) / 2 - // => hole < end / 2 if hole.pos() < end / 2 { let child = 2 * hole.pos() + 1; + debug_assert!(child == end - 1); + // If elements are not in order, move parent - // // SAFETY: The previous statements imply - // child is a valid index (child < end <= self.len()), - // and child != hole.pos(). + // child is a valid index (child < end <= self.len()), + // and child != hole.pos(). if hole.element() < unsafe { hole.get(child) } { // SAFETY: same as above unsafe { hole.move_to(child) }; From 15f64be7a91cf66c2de8e2f7945691ebe6758969 Mon Sep 17 00:00:00 2001 From: Saphereye Date: Mon, 1 Dec 2025 00:02:47 +0530 Subject: [PATCH 13/13] remove extra conditional --- library/alloc/src/collections/binary_heap/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 0245437aae297..ba27bd1cd6aef 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -867,10 +867,7 @@ impl BinaryHeap { // SAFETY: The previous statements imply // child is a valid index (child < end <= self.len()), // and child != hole.pos(). - if hole.element() < unsafe { hole.get(child) } { - // SAFETY: same as above - unsafe { hole.move_to(child) }; - } + unsafe { hole.move_to(child) }; } pos = hole.pos(); drop(hole);