@@ -2,7 +2,7 @@ use bidirectional_map::Bimap;
2
2
use disjoint_sets:: UnionFind ;
3
3
4
4
use std:: {
5
- collections:: HashSet ,
5
+ collections:: { HashMap , HashSet } ,
6
6
mem,
7
7
ops:: { Deref , DerefMut , Drop } ,
8
8
} ;
@@ -25,43 +25,34 @@ impl Optimizer {
25
25
}
26
26
27
27
pub fn optimize ( & self , schema : & mut Schema ) {
28
+ // <del>
28
29
// Note: Merging maps and unions at the same time may have produced results different from
29
30
// seperate merging (find map sets - merge - flatten - find union sets - merge - flatten).
30
31
// For simplicity, just take the first way.
31
- let sets = schema. arena . find_disjoint_sets ( |a, b| {
32
- if let ( Some ( a) , Some ( b) ) = ( a. as_map ( ) , b. as_map ( ) ) {
33
- self . to_merge_similar_datatypes && a. is_similar_to ( b)
34
- } else if let ( Some ( a) , Some ( b) ) = ( a. as_union ( ) , b. as_union ( ) ) {
35
- self . to_merge_same_unions && ( a. types == b. types )
36
- } else {
37
- // TODO: merge same array?
38
- false
39
- }
40
- } ) ;
41
- let mut ufarena = TypeArenaWithDSU :: from_type_arena ( & mut schema. arena ) ;
42
- for ( leader, mut set) in sets. into_iter ( ) {
43
- if ufarena. get ( leader) . map ( |r#type| {
44
- ( self . to_merge_similar_datatypes && r#type. is_map ( ) )
45
- || ( self . to_merge_same_unions && r#type. is_union ( ) )
46
- } ) == Some ( true )
47
- {
48
- set. insert ( leader) ; // leader in disjoint set is now a follower
49
-
50
- let compact_set = set
51
- . iter ( )
52
- . cloned ( )
53
- . filter ( |& r#type| ufarena. contains ( r#type) )
54
- . collect :: < Vec < ArenaIndex > > ( ) ;
55
- // unioned is now the new leader
56
- let _leader = union ( & mut ufarena, compact_set) ;
57
- // References to non-representative AreneIndex will be replaced automatically
58
- // when TypeArenaWithDSU is dropped
59
- }
60
- }
61
- // Although unioner always keeps the first map slot intact, there is no guarantee that
62
- // root would always be the first map in types to be unioned. So update it if necessary.
63
- schema. root = ufarena. find_representative ( schema. root ) . unwrap ( ) ;
64
- // arena.flatten();
32
+ // </del>
33
+ // Merging maps and unions in one pass leads to the issue #8. The reason might be some
34
+ // reentrancy issues in union (mem::replace?).
35
+ // TODO: merge same array?
36
+ schema. root = do_merge (
37
+ schema,
38
+ schema. arena . find_disjoint_sets ( |a, b| {
39
+ if let ( Some ( a) , Some ( b) ) = ( a. as_map ( ) , b. as_map ( ) ) {
40
+ self . to_merge_similar_datatypes && a. is_similar_to ( b)
41
+ } else {
42
+ false
43
+ }
44
+ } ) ,
45
+ ) ;
46
+ schema. root = do_merge (
47
+ schema,
48
+ schema. arena . find_disjoint_sets ( |a, b| {
49
+ if let ( Some ( a) , Some ( b) ) = ( a. as_union ( ) , b. as_union ( ) ) {
50
+ self . to_merge_same_unions && ( a. types == b. types )
51
+ } else {
52
+ false
53
+ }
54
+ } ) ,
55
+ ) ;
65
56
}
66
57
67
58
/* pub fn merge_same_union(&self, schema: &mut Schema) {
@@ -104,6 +95,29 @@ impl Optimizer {
104
95
*/
105
96
}
106
97
98
+ fn do_merge ( schema : & mut Schema , sets : HashMap < ArenaIndex , HashSet < ArenaIndex > > ) -> ArenaIndex {
99
+ let mut ufarena = TypeArenaWithDSU :: from_type_arena ( & mut schema. arena ) ;
100
+ for ( leader, mut set) in sets. into_iter ( ) {
101
+ set. insert ( leader) ; // leader in disjoint set is now a follower
102
+ if set. len ( ) <= 1 {
103
+ continue ;
104
+ }
105
+ let compact_set = set
106
+ . iter ( )
107
+ . cloned ( )
108
+ . filter ( |& r#type| ufarena. contains ( r#type) )
109
+ . collect :: < Vec < ArenaIndex > > ( ) ;
110
+ // unioned is now the new leader
111
+ let _leader = union ( & mut ufarena, compact_set) ;
112
+ // References to non-representative AreneIndex will be replaced automatically
113
+ // when TypeArenaWithDSU is dropped
114
+ }
115
+ // Although unioner always keeps the first map slot intact, there is no guarantee that
116
+ // root would always be the first map in types to be unioned. So update it if necessary.
117
+ ufarena. find_representative ( schema. root ) . unwrap ( )
118
+ // arena.flatten();
119
+ }
120
+
107
121
/// A wrapper around `&mut TypeArena` with a Disjoint Set Union. `get` and `get_mut` are wrapped
108
122
/// with DSU find to be DSU-aware. `remove_in_favor_of` is wrapped with DSU union.
109
123
///
0 commit comments