Skip to content

extra: Don't recurse in DList drop glue. #8295 #8297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions src/libextra/dlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ impl<T> Rawlink<T> {
Some(unsafe { cast::transmute(self.p) })
}
}

/// Return the `Rawlink` and replace with `Rawlink::none()`
fn take(&mut self) -> Rawlink<T> {
util::replace(self, Rawlink::none())
}
}

impl<T> Clone for Rawlink<T> {
Expand Down Expand Up @@ -280,13 +285,16 @@ impl<T> DList<T> {
/// Add all elements from `other` to the end of the list
///
/// O(1)
pub fn append(&mut self, other: DList<T>) {
pub fn append(&mut self, mut other: DList<T>) {
match self.list_tail.resolve() {
None => *self = other,
Some(tail) => {
match other {
DList{list_head: None, _} => return,
DList{list_head: Some(node), list_tail: o_tail, length: o_length} => {
// Carefully empty `other`.
let o_tail = other.list_tail.take();
let o_length = other.length;
match other.list_head.take() {
None => return,
Some(node) => {
tail.next = link_with_prev(node, self.list_tail);
self.list_tail = o_tail;
self.length += o_length;
Expand Down Expand Up @@ -404,6 +412,32 @@ impl<T: Ord> DList<T> {
}
}

#[unsafe_destructor]
impl<T> Drop for DList<T> {
fn drop(&self) {
let mut_self = unsafe {
cast::transmute_mut(self)
};
// Dissolve the dlist in backwards direction
// Just dropping the list_head can lead to stack exhaustion
// when length is >> 1_000_000
let mut tail = mut_self.list_tail;
loop {
match tail.resolve() {
None => break,
Some(prev) => {
prev.next.take(); // release ~Node<T>
tail = prev.prev;
}
}
}
mut_self.length = 0;
mut_self.list_head = None;
mut_self.list_tail = Rawlink::none();
}
}


impl<'self, A> Iterator<&'self A> for DListIterator<'self, A> {
#[inline]
fn next(&mut self) -> Option<&'self A> {
Expand Down