提交 4898a0de 编写于 作者: B Brian Anderson

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

The compiler-generated dtor for DList recurses deeply to drop Nodes.
For big lists this can overflow the stack.
上级 d6f23640
......@@ -92,6 +92,11 @@ fn resolve(&mut self) -> Option<&mut 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> {
......@@ -280,13 +285,16 @@ pub fn rotate_backward(&mut self) {
/// 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;
......@@ -404,6 +412,32 @@ pub fn insert_ordered(&mut self, elt: 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> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册