1
+ use crate :: frozen:: Frozen ;
1
2
use crate :: fx:: FxIndexSet ;
2
- use crate :: sync:: Lock ;
3
3
use rustc_index:: bit_set:: BitMatrix ;
4
4
use std:: fmt:: Debug ;
5
5
use std:: hash:: Hash ;
6
6
use std:: mem;
7
+ use std:: ops:: Deref ;
7
8
8
9
#[ cfg( test) ]
9
10
mod tests;
10
11
11
12
#[ derive( Clone , Debug ) ]
12
- pub struct TransitiveRelation < T > {
13
+ pub struct TransitiveRelationBuilder < T > {
13
14
// List of elements. This is used to map from a T to a usize.
14
15
elements : FxIndexSet < T > ,
15
16
16
17
// List of base edges in the graph. Require to compute transitive
17
18
// closure.
18
19
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 > > ,
19
26
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 > > ,
30
29
}
31
30
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 {
35
41
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 ( ) ) ,
39
44
}
40
45
}
41
46
}
42
47
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
+
43
55
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Debug ) ]
44
56
struct Index ( usize ) ;
45
57
@@ -49,7 +61,7 @@ struct Edge {
49
61
target : Index ,
50
62
}
51
63
52
- impl < T : Eq + Hash + Copy > TransitiveRelation < T > {
64
+ impl < T : Eq + Hash + Copy > TransitiveRelationBuilder < T > {
53
65
pub fn is_empty ( & self ) -> bool {
54
66
self . edges . is_empty ( )
55
67
}
@@ -63,23 +75,19 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
63
75
}
64
76
65
77
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) ;
71
79
Index ( index)
72
80
}
73
81
74
82
/// 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 > >
78
86
where
79
87
F : FnMut ( T ) -> Option < U > ,
80
88
U : Clone + Debug + Eq + Hash + Copy ,
81
89
{
82
- let mut result = TransitiveRelation :: default ( ) ;
90
+ let mut result = TransitiveRelationBuilder :: default ( ) ;
83
91
for edge in & self . edges {
84
92
result. add ( f ( self . elements [ edge. source . 0 ] ) ?, f ( self . elements [ edge. target . 0 ] ) ?) ;
85
93
}
@@ -93,10 +101,38 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
93
101
let edge = Edge { source : a, target : b } ;
94
102
if !self . edges . contains ( & edge) {
95
103
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 ) ;
96
118
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
+ }
99
122
}
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 ( ) )
100
136
}
101
137
102
138
/// Checks whether `a < target` (transitively)
@@ -322,30 +358,7 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
322
358
where
323
359
OP : FnOnce ( & BitMatrix < usize , usize > ) -> R ,
324
360
{
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 )
349
362
}
350
363
351
364
/// Lists all the base edges in the graph: the initial _non-transitive_ set of element
0 commit comments