@@ -2,32 +2,105 @@ use std::marker::PhantomData;
22
33use rustc_index:: vec:: { Idx , IndexVec } ;
44
5+ enum Undo < T > {
6+ Move { index : T , old : usize } ,
7+ Extend { group_index : usize , len : usize } ,
8+ NewGroup { index : T } ,
9+ }
10+
511pub 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 > ,
816 snapshots : usize ,
917}
1018
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+
1132impl < T : Idx > UnifyLog < T > {
1233 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+ }
1441 }
1542
1643 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+ }
2479 }
2580 }
26- root_ids. push ( other) ;
2781 }
2882
2983 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 ;
31104 }
32105
33106 pub fn snapshot ( & mut self ) -> Snapshot < T > {
@@ -44,8 +117,17 @@ impl<T: Idx> UnifyLog<T> {
44117
45118 pub fn rollback_to ( & mut self , snapshot : Snapshot < T > ) {
46119 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+ }
49131 }
50132 }
51133}
0 commit comments