@@ -2,32 +2,105 @@ use std::marker::PhantomData;
2
2
3
3
use rustc_index:: vec:: { Idx , IndexVec } ;
4
4
5
+ enum Undo < T > {
6
+ Move { index : T , old : usize } ,
7
+ Extend { group_index : usize , len : usize } ,
8
+ NewGroup { index : T } ,
9
+ }
10
+
5
11
pub struct UnifyLog < T : Idx > {
6
- unified_vars : IndexVec < T , Vec < T > > ,
7
- undo_log : Vec < ( T , u32 ) > ,
12
+ unified_vars : IndexVec < T , usize > ,
13
+ groups : Vec < Vec < T > > ,
14
+ undo_log : Vec < Undo < T > > ,
15
+ reference_counts : IndexVec < T , u32 > ,
8
16
snapshots : usize ,
9
17
}
10
18
19
+ fn pick2_mut < T , I : Idx > ( self_ : & mut [ T ] , a : I , b : I ) -> ( & mut T , & mut T ) {
20
+ let ( ai, bi) = ( a. index ( ) , b. index ( ) ) ;
21
+ assert ! ( ai != bi) ;
22
+
23
+ if ai < bi {
24
+ let ( c1, c2) = self_. split_at_mut ( bi) ;
25
+ ( & mut c1[ ai] , & mut c2[ 0 ] )
26
+ } else {
27
+ let ( c2, c1) = pick2_mut ( self_, b, a) ;
28
+ ( c1, c2)
29
+ }
30
+ }
31
+
11
32
impl < T : Idx > UnifyLog < T > {
12
33
pub fn new ( ) -> Self {
13
- UnifyLog { unified_vars : IndexVec :: new ( ) , undo_log : Vec :: new ( ) , snapshots : 0 }
34
+ UnifyLog {
35
+ unified_vars : IndexVec :: new ( ) ,
36
+ groups : Vec :: new ( ) ,
37
+ undo_log : Vec :: new ( ) ,
38
+ reference_counts : IndexVec :: new ( ) ,
39
+ snapshots : 0 ,
40
+ }
14
41
}
15
42
16
43
pub fn unify ( & mut self , root : T , other : T ) {
17
- self . unified_vars . ensure_contains_elem ( root, Vec :: new) ;
18
- self . unified_vars . ensure_contains_elem ( other, Vec :: new) ;
19
- let ( root_ids, other_ids) = self . unified_vars . pick2_mut ( root, other) ;
20
- self . undo_log . push ( ( root, root_ids. len ( ) as u32 ) ) ;
21
- for & other in & * other_ids {
22
- if !root_ids. contains ( & other) {
23
- root_ids. push ( other) ;
44
+ if !self . needs_log ( other) {
45
+ return ;
46
+ }
47
+ self . unified_vars . ensure_contains_elem ( root, usize:: max_value) ;
48
+ self . unified_vars . ensure_contains_elem ( other, usize:: max_value) ;
49
+ let mut root_group = self . unified_vars [ root] ;
50
+ let other_group = self . unified_vars [ other] ;
51
+
52
+ if other_group == usize:: max_value ( ) {
53
+ let root_vec = if root_group == usize:: max_value ( ) {
54
+ root_group = self . groups . len ( ) ;
55
+ self . unified_vars [ root] = root_group;
56
+ self . groups . push ( Vec :: new ( ) ) ;
57
+ self . undo_log . push ( Undo :: NewGroup { index : root } ) ;
58
+ self . groups . last_mut ( ) . unwrap ( )
59
+ } else {
60
+ let root_vec = & mut self . groups [ root_group] ;
61
+ self . undo_log . push ( Undo :: Extend { group_index : root_group, len : root_vec. len ( ) } ) ;
62
+ root_vec
63
+ } ;
64
+ root_vec. push ( other) ;
65
+ } else {
66
+ if root_group == usize:: max_value ( ) {
67
+ let group = & mut self . unified_vars [ root] ;
68
+ self . undo_log . push ( Undo :: Move { index : root, old : * group } ) ;
69
+ * group = other_group;
70
+ self . groups [ other_group] . push ( other) ;
71
+ } else {
72
+ let ( root_vec, other_vec) = pick2_mut ( & mut self . groups , root_group, other_group) ;
73
+ self . undo_log . push ( Undo :: Extend { group_index : root_group, len : root_vec. len ( ) } ) ;
74
+ root_vec. extend_from_slice ( other_vec) ;
75
+
76
+ if self . reference_counts . get ( other) . map_or ( false , |c| * c != 0 ) {
77
+ root_vec. push ( other) ;
78
+ }
24
79
}
25
80
}
26
- root_ids. push ( other) ;
27
81
}
28
82
29
83
pub fn get ( & self , root : T ) -> & [ T ] {
30
- self . unified_vars . get ( root) . map ( |v| & v[ ..] ) . unwrap_or ( & [ ] [ ..] )
84
+ match self . unified_vars . get ( root) {
85
+ Some ( group) => match self . groups . get ( * group) {
86
+ Some ( v) => v,
87
+ None => & [ ] ,
88
+ } ,
89
+ None => & [ ] ,
90
+ }
91
+ }
92
+
93
+ pub fn needs_log ( & self , vid : T ) -> bool {
94
+ !self . get ( vid) . is_empty ( ) || self . reference_counts . get ( vid) . map_or ( false , |c| * c != 0 )
95
+ }
96
+
97
+ pub fn watch_variable ( & mut self , index : T ) {
98
+ self . reference_counts . ensure_contains_elem ( index, || 0 ) ;
99
+ self . reference_counts [ index] += 1 ;
100
+ }
101
+
102
+ pub fn unwatch_variable ( & mut self , index : T ) {
103
+ self . reference_counts [ index] -= 1 ;
31
104
}
32
105
33
106
pub fn snapshot ( & mut self ) -> Snapshot < T > {
@@ -44,8 +117,17 @@ impl<T: Idx> UnifyLog<T> {
44
117
45
118
pub fn rollback_to ( & mut self , snapshot : Snapshot < T > ) {
46
119
self . snapshots -= 1 ;
47
- for ( index, len) in self . undo_log . drain ( snapshot. undo_log_len as usize ..) {
48
- self . unified_vars [ index] . truncate ( len as usize ) ;
120
+ for undo in self . undo_log . drain ( snapshot. undo_log_len as usize ..) . rev ( ) {
121
+ match undo {
122
+ Undo :: Extend { group_index, len } => {
123
+ self . groups [ group_index] . truncate ( len as usize )
124
+ }
125
+ Undo :: Move { index, old } => self . unified_vars [ index] = old,
126
+ Undo :: NewGroup { index } => {
127
+ self . groups . pop ( ) ;
128
+ self . unified_vars [ index] = usize:: max_value ( ) ;
129
+ }
130
+ }
49
131
}
50
132
}
51
133
}
0 commit comments