1+ use crate :: frozen:: Frozen ;
12use crate :: fx:: FxIndexSet ;
2- use crate :: sync:: Lock ;
33use rustc_index:: bit_set:: BitMatrix ;
44use std:: fmt:: Debug ;
55use std:: hash:: Hash ;
66use std:: mem;
7+ use std:: ops:: Deref ;
78
89#[ cfg( test) ]
910mod tests;
1011
1112#[ derive( Clone , Debug ) ]
12- pub struct TransitiveRelation < T > {
13+ pub struct TransitiveRelationBuilder < T > {
1314 // List of elements. This is used to map from a T to a usize.
1415 elements : FxIndexSet < T > ,
1516
1617 // List of base edges in the graph. Require to compute transitive
1718 // closure.
1819 edges : Vec < Edge > ,
20+ }
21+
22+ #[ derive( Debug ) ]
23+ pub struct TransitiveRelation < T > {
24+ // Frozen transitive relation elements and edges.
25+ builder : Frozen < TransitiveRelationBuilder < T > > ,
1926
20- // This is a cached transitive closure derived from the edges.
21- // Currently, we build it lazily and just throw out any existing
22- // copy whenever a new edge is added. (The Lock is to permit
23- // the lazy computation.) This is kind of silly, except for the
24- // fact its size is tied to `self.elements.len()`, so I wanted to
25- // wait before building it up to avoid reallocating as new edges
26- // are added with new elements. Perhaps better would be to ask the
27- // user for a batch of edges to minimize this effect, but I
28- // already wrote the code this way. :P -nmatsakis
29- closure : Lock < Option < BitMatrix < usize , usize > > > ,
27+ // Cached transitive closure derived from the edges.
28+ closure : Frozen < BitMatrix < usize , usize > > ,
3029}
3130
32- // HACK(eddyb) manual impl avoids `Default` bound on `T`.
33- impl < T : Eq + Hash > Default for TransitiveRelation < T > {
34- fn default ( ) -> Self {
31+ impl < T > Deref for TransitiveRelation < T > {
32+ type Target = Frozen < TransitiveRelationBuilder < T > > ;
33+
34+ fn deref ( & self ) -> & Self :: Target {
35+ & self . builder
36+ }
37+ }
38+
39+ impl < T : Clone > Clone for TransitiveRelation < T > {
40+ fn clone ( & self ) -> Self {
3541 TransitiveRelation {
36- elements : Default :: default ( ) ,
37- edges : Default :: default ( ) ,
38- closure : Default :: default ( ) ,
42+ builder : Frozen :: freeze ( self . builder . deref ( ) . clone ( ) ) ,
43+ closure : Frozen :: freeze ( self . closure . deref ( ) . clone ( ) ) ,
3944 }
4045 }
4146}
4247
48+ // HACK(eddyb) manual impl avoids `Default` bound on `T`.
49+ impl < T : Eq + Hash > Default for TransitiveRelationBuilder < T > {
50+ fn default ( ) -> Self {
51+ TransitiveRelationBuilder { elements : Default :: default ( ) , edges : Default :: default ( ) }
52+ }
53+ }
54+
4355#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Debug ) ]
4456struct Index ( usize ) ;
4557
@@ -49,7 +61,7 @@ struct Edge {
4961 target : Index ,
5062}
5163
52- impl < T : Eq + Hash + Copy > TransitiveRelation < T > {
64+ impl < T : Eq + Hash + Copy > TransitiveRelationBuilder < T > {
5365 pub fn is_empty ( & self ) -> bool {
5466 self . edges . is_empty ( )
5567 }
@@ -63,23 +75,19 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
6375 }
6476
6577 fn add_index ( & mut self , a : T ) -> Index {
66- let ( index, added) = self . elements . insert_full ( a) ;
67- if added {
68- // if we changed the dimensions, clear the cache
69- * self . closure . get_mut ( ) = None ;
70- }
78+ let ( index, _added) = self . elements . insert_full ( a) ;
7179 Index ( index)
7280 }
7381
7482 /// Applies the (partial) function to each edge and returns a new
75- /// relation. If `f` returns `None` for any end-point, returns
76- /// `None`.
77- pub fn maybe_map < F , U > ( & self , mut f : F ) -> Option < TransitiveRelation < U > >
83+ /// relation builder . If `f` returns `None` for any end-point,
84+ /// returns `None`.
85+ pub fn maybe_map < F , U > ( & self , mut f : F ) -> Option < TransitiveRelationBuilder < U > >
7886 where
7987 F : FnMut ( T ) -> Option < U > ,
8088 U : Clone + Debug + Eq + Hash + Copy ,
8189 {
82- let mut result = TransitiveRelation :: default ( ) ;
90+ let mut result = TransitiveRelationBuilder :: default ( ) ;
8391 for edge in & self . edges {
8492 result. add ( f ( self . elements [ edge. source . 0 ] ) ?, f ( self . elements [ edge. target . 0 ] ) ?) ;
8593 }
@@ -93,10 +101,38 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
93101 let edge = Edge { source : a, target : b } ;
94102 if !self . edges . contains ( & edge) {
95103 self . edges . push ( edge) ;
104+ }
105+ }
106+
107+ /// Compute the transitive closure derived from the edges, and converted to
108+ /// the final result. After this, all elements will be immutable to maintain
109+ /// the correctness of the result.
110+ pub fn freeze ( self ) -> TransitiveRelation < T > {
111+ let mut matrix = BitMatrix :: new ( self . elements . len ( ) , self . elements . len ( ) ) ;
112+ let mut changed = true ;
113+ while changed {
114+ changed = false ;
115+ for edge in & self . edges {
116+ // add an edge from S -> T
117+ changed |= matrix. insert ( edge. source . 0 , edge. target . 0 ) ;
96118
97- // added an edge, clear the cache
98- * self . closure . get_mut ( ) = None ;
119+ // add all outgoing edges from T into S
120+ changed |= matrix. union_rows ( edge. target . 0 , edge. source . 0 ) ;
121+ }
99122 }
123+ TransitiveRelation { builder : Frozen :: freeze ( self ) , closure : Frozen :: freeze ( matrix) }
124+ }
125+ }
126+
127+ impl < T : Eq + Hash + Copy > TransitiveRelation < T > {
128+ /// Applies the (partial) function to each edge and returns a new
129+ /// relation including transitive closures.
130+ pub fn maybe_map < F , U > ( & self , f : F ) -> Option < TransitiveRelation < U > >
131+ where
132+ F : FnMut ( T ) -> Option < U > ,
133+ U : Clone + Debug + Eq + Hash + Copy ,
134+ {
135+ Some ( self . builder . maybe_map ( f) ?. freeze ( ) )
100136 }
101137
102138 /// Checks whether `a < target` (transitively)
@@ -322,30 +358,7 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
322358 where
323359 OP : FnOnce ( & BitMatrix < usize , usize > ) -> R ,
324360 {
325- let mut closure_cell = self . closure . borrow_mut ( ) ;
326- let mut closure = closure_cell. take ( ) ;
327- if closure. is_none ( ) {
328- closure = Some ( self . compute_closure ( ) ) ;
329- }
330- let result = op ( closure. as_ref ( ) . unwrap ( ) ) ;
331- * closure_cell = closure;
332- result
333- }
334-
335- fn compute_closure ( & self ) -> BitMatrix < usize , usize > {
336- let mut matrix = BitMatrix :: new ( self . elements . len ( ) , self . elements . len ( ) ) ;
337- let mut changed = true ;
338- while changed {
339- changed = false ;
340- for edge in & self . edges {
341- // add an edge from S -> T
342- changed |= matrix. insert ( edge. source . 0 , edge. target . 0 ) ;
343-
344- // add all outgoing edges from T into S
345- changed |= matrix. union_rows ( edge. target . 0 , edge. source . 0 ) ;
346- }
347- }
348- matrix
361+ op ( & self . closure )
349362 }
350363
351364 /// Lists all the base edges in the graph: the initial _non-transitive_ set of element
0 commit comments