mirror of
https://github.com/rust-lang/cargo
synced 2024-09-20 00:02:05 +00:00
Avoid stack overflow when dropping RcList
Turn recursion into a loop
This commit is contained in:
parent
c9fd94a464
commit
19e0fa641d
|
@ -49,7 +49,6 @@ use std::cmp::Ordering;
|
|||
use std::collections::{HashSet, HashMap, BinaryHeap, BTreeMap};
|
||||
use std::iter::FromIterator;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -256,28 +255,37 @@ impl<'a> Iterator for DepsNotReplaced<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
enum RcList<T> {
|
||||
Data(Rc<(T, RcList<T>)>),
|
||||
Empty,
|
||||
struct RcList<T> {
|
||||
head: Option<Rc<(T, RcList<T>)>>
|
||||
}
|
||||
|
||||
impl<T> RcList<T> {
|
||||
fn new() -> RcList<T> {
|
||||
RcList::Empty
|
||||
RcList { head: None }
|
||||
}
|
||||
|
||||
fn push(&mut self, data: T) {
|
||||
let node = Rc::new((data, mem::replace(self, RcList::Empty)));
|
||||
*self = RcList::Data(node);
|
||||
let node = Rc::new((data, RcList { head: self.head.take() }));
|
||||
self.head = Some(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Not derived to avoid `T: Clone`
|
||||
impl<T> Clone for RcList<T> {
|
||||
fn clone(&self) -> RcList<T> {
|
||||
match *self {
|
||||
RcList::Data(ref d) => RcList::Data(d.clone()),
|
||||
RcList::Empty => RcList::Empty,
|
||||
RcList { head: self.head.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid stack overflows on drop by turning recursion into a loop
|
||||
impl<T> Drop for RcList<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut cur = self.head.take();
|
||||
while let Some(head) = cur {
|
||||
match Rc::try_unwrap(head) {
|
||||
Ok((_data, mut next)) => cur = next.head.take(),
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1085,10 +1093,10 @@ impl<'a> Context<'a> {
|
|||
fn resolve_replacements(&self) -> HashMap<PackageId, PackageId> {
|
||||
let mut replacements = HashMap::new();
|
||||
let mut cur = &self.resolve_replacements;
|
||||
while let RcList::Data(ref d) = *cur {
|
||||
let (k, v) = d.0.clone();
|
||||
while let Some(ref node) = cur.head {
|
||||
let (k, v) = node.0.clone();
|
||||
replacements.insert(k, v);
|
||||
cur = &d.1;
|
||||
cur = &node.1;
|
||||
}
|
||||
return replacements
|
||||
}
|
||||
|
@ -1096,12 +1104,12 @@ impl<'a> Context<'a> {
|
|||
fn graph(&self) -> Graph<PackageId> {
|
||||
let mut graph = Graph::new();
|
||||
let mut cur = &self.resolve_graph;
|
||||
while let RcList::Data(ref d) = *cur {
|
||||
match d.0 {
|
||||
while let Some(ref node) = cur.head {
|
||||
match node.0 {
|
||||
GraphNode::Add(ref p) => graph.add(p.clone(), &[]),
|
||||
GraphNode::Link(ref a, ref b) => graph.link(a.clone(), b.clone()),
|
||||
}
|
||||
cur = &d.1;
|
||||
cur = &node.1;
|
||||
}
|
||||
return graph
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue