|
153 | 153 | use core::prelude::*;
|
154 | 154 |
|
155 | 155 | use core::iter::{FromIterator};
|
156 |
| -use core::mem::{zeroed, replace, swap}; |
| 156 | +use core::mem::swap; |
157 | 157 | use core::ptr;
|
158 | 158 |
|
159 | 159 | use slice;
|
@@ -484,44 +484,43 @@ impl<T: Ord> BinaryHeap<T> {
|
484 | 484 |
|
485 | 485 | // The implementations of sift_up and sift_down use unsafe blocks in
|
486 | 486 | // order to move an element out of the vector (leaving behind a
|
487 |
| - // zeroed element), shift along the others and move it back into the |
488 |
| - // vector over the junk element. This reduces the constant factor |
489 |
| - // compared to using swaps, which involves twice as many moves. |
490 |
| - fn sift_up(&mut self, start: usize, mut pos: usize) { |
| 487 | + // hole), shift along the others and move the removed element back into the |
| 488 | + // vector at the final location of the hole. |
| 489 | + // The `Hole` type is used to represent this, and make sure |
| 490 | + // the hole is filled back at the end of its scope, even on panic. |
| 491 | + // Using a hole reduces the constant factor compared to using swaps, |
| 492 | + // which involves twice as many moves. |
| 493 | + fn sift_up(&mut self, start: usize, pos: usize) { |
491 | 494 | unsafe {
|
492 |
| - let new = replace(&mut self.data[pos], zeroed()); |
| 495 | + // Take out the value at `pos` and create a hole. |
| 496 | + let mut hole = Hole::new(&mut self.data, pos); |
493 | 497 |
|
494 |
| - while pos > start { |
495 |
| - let parent = (pos - 1) >> 1; |
496 |
| - |
497 |
| - if new <= self.data[parent] { break; } |
498 |
| - |
499 |
| - let x = replace(&mut self.data[parent], zeroed()); |
500 |
| - ptr::write(&mut self.data[pos], x); |
501 |
| - pos = parent; |
| 498 | + while hole.pos() > start { |
| 499 | + let parent = (hole.pos() - 1) >> 1; |
| 500 | + if hole.removed() <= hole.get(parent) { break } |
| 501 | + hole.move_to(parent); |
502 | 502 | }
|
503 |
| - ptr::write(&mut self.data[pos], new); |
504 | 503 | }
|
505 | 504 | }
|
506 | 505 |
|
507 | 506 | fn sift_down_range(&mut self, mut pos: usize, end: usize) {
|
508 | 507 | unsafe {
|
509 | 508 | let start = pos;
|
510 |
| - let new = replace(&mut self.data[pos], zeroed()); |
511 |
| - |
512 |
| - let mut child = 2 * pos + 1; |
513 |
| - while child < end { |
514 |
| - let right = child + 1; |
515 |
| - if right < end && !(self.data[child] > self.data[right]) { |
516 |
| - child = right; |
| 509 | + { |
| 510 | + let mut hole = Hole::new(&mut self.data, pos); |
| 511 | + let mut child = 2 * pos + 1; |
| 512 | + while child < end { |
| 513 | + let right = child + 1; |
| 514 | + if right < end && !(hole.get(child) > hole.get(right)) { |
| 515 | + child = right; |
| 516 | + } |
| 517 | + hole.move_to(child); |
| 518 | + child = 2 * hole.pos() + 1; |
517 | 519 | }
|
518 |
| - let x = replace(&mut self.data[child], zeroed()); |
519 |
| - ptr::write(&mut self.data[pos], x); |
520 |
| - pos = child; |
521 |
| - child = 2 * pos + 1; |
| 520 | + |
| 521 | + pos = hole.pos; |
522 | 522 | }
|
523 | 523 |
|
524 |
| - ptr::write(&mut self.data[pos], new); |
525 | 524 | self.sift_up(start, pos);
|
526 | 525 | }
|
527 | 526 | }
|
@@ -554,6 +553,70 @@ impl<T: Ord> BinaryHeap<T> {
|
554 | 553 | pub fn clear(&mut self) { self.drain(); }
|
555 | 554 | }
|
556 | 555 |
|
| 556 | +/// Hole represents a hole in a slice i.e. an index without valid value |
| 557 | +/// (because it was moved from or duplicated). |
| 558 | +/// In drop, `Hole` will restore the slice by filling the hole |
| 559 | +/// position with the value that was originally removed. |
| 560 | +struct Hole<'a, T: 'a> { |
| 561 | + data: &'a mut [T], |
| 562 | + elt: Option<T>, |
| 563 | + pos: usize, |
| 564 | +} |
| 565 | + |
| 566 | +impl<'a, T> Hole<'a, T> { |
| 567 | + /// Create a new Hole at index `pos`. |
| 568 | + pub fn new(data: &'a mut [T], pos: usize) -> Self { |
| 569 | + unsafe { |
| 570 | + let elt = ptr::read(&data[pos]); |
| 571 | + Hole { |
| 572 | + data: data, |
| 573 | + elt: Some(elt), |
| 574 | + pos: pos, |
| 575 | + } |
| 576 | + } |
| 577 | + } |
| 578 | + |
| 579 | + #[inline(always)] |
| 580 | + pub fn pos(&self) -> usize { self.pos } |
| 581 | + |
| 582 | + /// Return a reference to the element removed |
| 583 | + #[inline(always)] |
| 584 | + pub fn removed(&self) -> &T { |
| 585 | + self.elt.as_ref().unwrap() |
| 586 | + } |
| 587 | + |
| 588 | + /// Return a reference to the element at `index`. |
| 589 | + /// |
| 590 | + /// Panics if the index is out of bounds. |
| 591 | + /// |
| 592 | + /// Unsafe because index must not equal pos. |
| 593 | + #[inline(always)] |
| 594 | + pub unsafe fn get(&self, index: usize) -> &T { |
| 595 | + debug_assert!(index != self.pos); |
| 596 | + &self.data[index] |
| 597 | + } |
| 598 | + |
| 599 | + /// Move hole to new location |
| 600 | + #[inline(always)] |
| 601 | + pub unsafe fn move_to(&mut self, index: usize) { |
| 602 | + debug_assert!(index != self.pos); |
| 603 | + let old_pos = self.pos; |
| 604 | + let x = ptr::read(&mut self.data[index]); |
| 605 | + ptr::write(&mut self.data[old_pos], x); |
| 606 | + self.pos = index; |
| 607 | + } |
| 608 | +} |
| 609 | + |
| 610 | +impl<'a, T> Drop for Hole<'a, T> { |
| 611 | + fn drop(&mut self) { |
| 612 | + // fill the hole again |
| 613 | + unsafe { |
| 614 | + let pos = self.pos; |
| 615 | + ptr::write(&mut self.data[pos], self.elt.take().unwrap()); |
| 616 | + } |
| 617 | + } |
| 618 | +} |
| 619 | + |
557 | 620 | /// `BinaryHeap` iterator.
|
558 | 621 | #[stable(feature = "rust1", since = "1.0.0")]
|
559 | 622 | pub struct Iter <'a, T: 'a> {
|
|
0 commit comments