diff options
| author | bors <bors@rust-lang.org> | 2013-08-04 19:52:57 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-08-04 19:52:57 -0700 |
| commit | 6c12ca3ac2d0db3f9636e16fc5a507a12f313e7f (patch) | |
| tree | 2d75d8ba37f5d36072016bc26691239a9649fa8f /src | |
| parent | dc5b0b94101a1fb9094b62ed1bb1b0be3b073fcc (diff) | |
| parent | 4898a0de04600afefcb095b55ea0d924f125a892 (diff) | |
| download | rust-6c12ca3ac2d0db3f9636e16fc5a507a12f313e7f.tar.gz rust-6c12ca3ac2d0db3f9636e16fc5a507a12f313e7f.zip | |
auto merge of #8297 : brson/rust/dlist-dtor, r=brson
The compiler-generated dtor for DList recurses deeply to drop Nodes. For big lists this can overflow the stack. This is a problem for the new scheduler, where split stacks are not implemented. Thanks @blake2-ppc
Diffstat (limited to 'src')
| -rw-r--r-- | src/libextra/dlist.rs | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 4142bdadaf6..75487a44f26 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -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> { @@ -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; @@ -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> { |
