From: Niko Matsakis Date: Sun, 23 Apr 2017 09:14:10 +0000 (-0400) Subject: make transitive relation use a hash map X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=b175aef0c40d0b60316fabc6b4023c60c5bc832e;p=rust.git make transitive relation use a hash map --- diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index b0fca5c0ff3..0d166cc0b9e 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,21 +9,23 @@ // except according to those terms. use bitvec::BitMatrix; -use stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use fx::FxHashMap; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; +use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::cell::RefCell; use std::fmt::Debug; +use std::hash::Hash; use std::mem; - #[derive(Clone)] -pub struct TransitiveRelation { - // List of elements. This is used to map from a T to a usize. We - // expect domain to be small so just use a linear list versus a - // hashmap or something. +pub struct TransitiveRelation { + // List of elements. This is used to map from a T to a usize. elements: Vec, + // Maps each element to an index. + map: FxHashMap, + // List of base edges in the graph. Require to compute transitive // closure. edges: Vec, @@ -40,19 +42,20 @@ pub struct TransitiveRelation { closure: RefCell>, } -#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] struct Index(usize); -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] struct Edge { source: Index, target: Index, } -impl TransitiveRelation { +impl TransitiveRelation { pub fn new() -> TransitiveRelation { TransitiveRelation { elements: vec![], + map: FxHashMap(), edges: vec![], closure: RefCell::new(None), } @@ -63,21 +66,27 @@ pub fn is_empty(&self) -> bool { } fn index(&self, a: &T) -> Option { - self.elements.iter().position(|e| *e == *a).map(Index) + self.map.get(a).cloned() } fn add_index(&mut self, a: T) -> Index { - match self.index(&a) { - Some(i) => i, - None => { - self.elements.push(a); - - // if we changed the dimensions, clear the cache - *self.closure.borrow_mut() = None; - - Index(self.elements.len() - 1) - } - } + let &mut TransitiveRelation { + ref mut elements, + ref closure, + ref mut map, + .. + } = self; + + map.entry(a.clone()) + .or_insert_with(|| { + elements.push(a); + + // if we changed the dimensions, clear the cache + *closure.borrow_mut() = None; + + Index(elements.len() - 1) + }) + .clone() } /// Applies the (partial) function to each edge and returns a new @@ -85,7 +94,7 @@ fn add_index(&mut self, a: T) -> Index { /// `None`. pub fn maybe_map(&self, mut f: F) -> Option> where F: FnMut(&T) -> Option, - U: Debug + PartialEq, + U: Clone + Debug + Eq + Hash + Clone, { let mut result = TransitiveRelation::new(); for edge in &self.edges { @@ -335,7 +344,7 @@ fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { } impl Encodable for TransitiveRelation - where T: Encodable + Debug + PartialEq + where T: Clone + Encodable + Debug + Eq + Hash + Clone { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_struct("TransitiveRelation", 2, |s| { @@ -347,19 +356,23 @@ fn encode(&self, s: &mut E) -> Result<(), E::Error> { } impl Decodable for TransitiveRelation - where T: Decodable + Debug + PartialEq + where T: Clone + Decodable + Debug + Eq + Hash + Clone { fn decode(d: &mut D) -> Result { d.read_struct("TransitiveRelation", 2, |d| { - let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; + let elements: Vec = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?; - Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) }) + let map = elements.iter() + .enumerate() + .map(|(index, elem)| (elem.clone(), Index(index))) + .collect(); + Ok(TransitiveRelation { elements, edges, map, closure: RefCell::new(None) }) }) } } impl HashStable for TransitiveRelation - where T: HashStable + PartialEq + Debug + where T: HashStable + Eq + Debug + Clone + Hash { fn hash_stable(&self, hcx: &mut CTX, @@ -369,6 +382,8 @@ fn hash_stable(&self, let TransitiveRelation { ref elements, ref edges, + // "map" is just a copy of elements vec + map: _, // "closure" is just a copy of the data above closure: _ } = *self;