@@ -2,7 +2,7 @@ use bidirectional_map::Bimap;
22use disjoint_sets:: UnionFind ;
33
44use std:: {
5- collections:: HashSet ,
5+ collections:: { HashMap , HashSet } ,
66 mem,
77 ops:: { Deref , DerefMut , Drop } ,
88} ;
@@ -25,43 +25,34 @@ impl Optimizer {
2525 }
2626
2727 pub fn optimize ( & self , schema : & mut Schema ) {
28+ // <del>
2829 // Note: Merging maps and unions at the same time may have produced results different from
2930 // seperate merging (find map sets - merge - flatten - find union sets - merge - flatten).
3031 // 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+ ) ;
6556 }
6657
6758 /* pub fn merge_same_union(&self, schema: &mut Schema) {
@@ -104,6 +95,29 @@ impl Optimizer {
10495 */
10596}
10697
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+
107121/// A wrapper around `&mut TypeArena` with a Disjoint Set Union. `get` and `get_mut` are wrapped
108122/// with DSU find to be DSU-aware. `remove_in_favor_of` is wrapped with DSU union.
109123///
0 commit comments