@@ -11,17 +11,18 @@ impl<'a> FileDependencyRelation<'a> {
1111 Self { dependencies }
1212 }
1313
14- pub fn get_best_analysis_order ( & self , file_ids : Vec < FileId > ) -> Vec < FileId > {
14+ pub fn get_best_analysis_order (
15+ & self ,
16+ file_ids : & [ FileId ] ,
17+ metas : & HashSet < FileId > ,
18+ ) -> Vec < FileId > {
1519 let n = file_ids. len ( ) ;
16- if n == 0 || self . dependencies . is_empty ( ) {
17- return file_ids;
20+ if n < 2 {
21+ return file_ids. to_vec ( ) ;
1822 }
1923
20- let file_to_idx: HashMap < FileId , usize > = file_ids
21- . iter ( )
22- . enumerate ( )
23- . map ( |( i, & f) | ( f, i) )
24- . collect ( ) ;
24+ let file_to_idx: HashMap < FileId , usize > =
25+ file_ids. iter ( ) . enumerate ( ) . map ( |( i, & f) | ( f, i) ) . collect ( ) ;
2526
2627 let mut in_degree = vec ! [ 0usize ; n] ;
2728 let mut adjacency: Vec < Vec < usize > > = vec ! [ Vec :: new( ) ; n] ;
@@ -39,23 +40,53 @@ impl<'a> FileDependencyRelation<'a> {
3940 let mut result = Vec :: with_capacity ( n) ;
4041 let mut queue = VecDeque :: with_capacity ( n) ;
4142
43+ // 入度为0的节点,按优先级排序:meta文件优先,然后按FileId排序
4244 let mut zero_in_degree: Vec < usize > = ( 0 ..n) . filter ( |& i| in_degree[ i] == 0 ) . collect ( ) ;
43- zero_in_degree. sort_by_key ( |& i| file_ids[ i] ) ;
45+ zero_in_degree. sort_by ( |& a, & b| {
46+ let a_is_meta = metas. contains ( & file_ids[ a] ) ;
47+ let b_is_meta = metas. contains ( & file_ids[ b] ) ;
48+ // meta文件优先(true > false,所以反过来比较)
49+ match ( b_is_meta, a_is_meta) {
50+ ( true , false ) => std:: cmp:: Ordering :: Greater ,
51+ ( false , true ) => std:: cmp:: Ordering :: Less ,
52+ _ => file_ids[ a] . cmp ( & file_ids[ b] ) ,
53+ }
54+ } ) ;
4455
4556 for idx in zero_in_degree {
4657 queue. push_back ( idx) ;
4758 }
4859
4960 while let Some ( idx) = queue. pop_front ( ) {
5061 result. push ( file_ids[ idx] ) ;
62+
63+ // 收集新的入度为0的节点
64+ let mut new_zero: Vec < usize > = Vec :: new ( ) ;
5165 for & neighbor in & adjacency[ idx] {
5266 in_degree[ neighbor] -= 1 ;
5367 if in_degree[ neighbor] == 0 {
54- queue . push_back ( neighbor) ;
68+ new_zero . push ( neighbor) ;
5569 }
5670 }
71+
72+ // 同样按优先级排序后加入队列
73+ if new_zero. len ( ) > 1 {
74+ new_zero. sort_by ( |& a, & b| {
75+ let a_is_meta = metas. contains ( & file_ids[ a] ) ;
76+ let b_is_meta = metas. contains ( & file_ids[ b] ) ;
77+ match ( b_is_meta, a_is_meta) {
78+ ( true , false ) => std:: cmp:: Ordering :: Greater ,
79+ ( false , true ) => std:: cmp:: Ordering :: Less ,
80+ _ => file_ids[ a] . cmp ( & file_ids[ b] ) ,
81+ }
82+ } ) ;
83+ }
84+ for neighbor in new_zero {
85+ queue. push_back ( neighbor) ;
86+ }
5787 }
5888
89+ // 处理循环依赖
5990 if result. len ( ) < n {
6091 for ( idx, & deg) in in_degree. iter ( ) . enumerate ( ) {
6192 if deg > 0 {
@@ -109,7 +140,8 @@ mod tests {
109140 // 文件2没有依赖
110141 map. insert ( FileId :: new ( 2 ) , HashSet :: new ( ) ) ;
111142 let rel = FileDependencyRelation :: new ( & map) ;
112- let result = rel. get_best_analysis_order ( vec ! [ FileId :: new( 1 ) , FileId :: new( 2 ) ] ) ;
143+ let result =
144+ rel. get_best_analysis_order ( & [ FileId :: new ( 1 ) , FileId :: new ( 2 ) ] , & HashSet :: default ( ) ) ;
113145 // 文件2没有依赖,应该在前;文件1依赖文件2,在后
114146 assert_eq ! ( result, vec![ FileId :: new( 2 ) , FileId :: new( 1 ) ] ) ;
115147 }
@@ -133,7 +165,8 @@ mod tests {
133165 // 文件3没有依赖
134166 map. insert ( 3 . into ( ) , HashSet :: new ( ) ) ;
135167 let rel = FileDependencyRelation :: new ( & map) ;
136- let result = rel. get_best_analysis_order ( vec ! [ 1 . into( ) , 2 . into( ) , 3 . into( ) ] ) ;
168+ let result =
169+ rel. get_best_analysis_order ( & [ 1 . into ( ) , 2 . into ( ) , 3 . into ( ) ] , & HashSet :: default ( ) ) ;
137170 // 文件3没有依赖,应该在最前面;然后是2,最后是1
138171 assert_eq ! ( result, vec![ 3 . into( ) , 2 . into( ) , 1 . into( ) ] ) ;
139172 }
@@ -159,12 +192,15 @@ mod tests {
159192 map. insert ( FileId :: new ( 4 ) , HashSet :: new ( ) ) ;
160193
161194 let rel = FileDependencyRelation :: new ( & map) ;
162- let result = rel. get_best_analysis_order ( vec ! [
163- FileId :: new( 1 ) ,
164- FileId :: new( 2 ) ,
165- FileId :: new( 3 ) ,
166- FileId :: new( 4 ) ,
167- ] ) ;
195+ let result = rel. get_best_analysis_order (
196+ & [
197+ FileId :: new ( 1 ) ,
198+ FileId :: new ( 2 ) ,
199+ FileId :: new ( 3 ) ,
200+ FileId :: new ( 4 ) ,
201+ ] ,
202+ & HashSet :: default ( ) ,
203+ ) ;
168204
169205 // 文件3和4没有依赖,应该在前面
170206 assert_eq ! ( result[ 0 ] , FileId :: new( 3 ) ) ;
@@ -190,4 +226,75 @@ mod tests {
190226 result. sort ( ) ;
191227 assert_eq ! ( result, vec![ FileId :: new( 1 ) , FileId :: new( 2 ) , FileId :: new( 4 ) ] ) ;
192228 }
229+
230+ #[ test]
231+ fn test_meta_files_first ( ) {
232+ let mut map = HashMap :: new ( ) ;
233+ // 所有文件都没有依赖
234+ map. insert ( FileId :: new ( 1 ) , HashSet :: new ( ) ) ;
235+ map. insert ( FileId :: new ( 2 ) , HashSet :: new ( ) ) ;
236+ map. insert ( FileId :: new ( 3 ) , HashSet :: new ( ) ) ;
237+ map. insert ( FileId :: new ( 4 ) , HashSet :: new ( ) ) ;
238+
239+ let rel = FileDependencyRelation :: new ( & map) ;
240+
241+ // 文件2和4是meta文件
242+ let mut metas = HashSet :: new ( ) ;
243+ metas. insert ( FileId :: new ( 2 ) ) ;
244+ metas. insert ( FileId :: new ( 4 ) ) ;
245+
246+ let result = rel. get_best_analysis_order (
247+ & [
248+ FileId :: new ( 1 ) ,
249+ FileId :: new ( 2 ) ,
250+ FileId :: new ( 3 ) ,
251+ FileId :: new ( 4 ) ,
252+ ] ,
253+ & metas,
254+ ) ;
255+
256+ // meta文件应该在前面(2和4),非meta文件在后面(1和3)
257+ assert ! ( metas. contains( & result[ 0 ] ) , "第一个应该是meta文件" ) ;
258+ assert ! ( metas. contains( & result[ 1 ] ) , "第二个应该是meta文件" ) ;
259+ assert ! ( !metas. contains( & result[ 2 ] ) , "第三个应该是非meta文件" ) ;
260+ assert ! ( !metas. contains( & result[ 3 ] ) , "第四个应该是非meta文件" ) ;
261+ }
262+
263+ #[ test]
264+ fn test_meta_with_dependencies ( ) {
265+ let mut map = HashMap :: new ( ) ;
266+ // File 1 depends on file 2 (meta)
267+ map. insert ( FileId :: new ( 1 ) , {
268+ let mut s = HashSet :: new ( ) ;
269+ s. insert ( FileId :: new ( 2 ) ) ;
270+ s
271+ } ) ;
272+ // File 2 (meta) has no dependencies
273+ map. insert ( FileId :: new ( 2 ) , HashSet :: new ( ) ) ;
274+ // File 3 has no dependencies
275+ map. insert ( FileId :: new ( 3 ) , HashSet :: new ( ) ) ;
276+
277+ let rel = FileDependencyRelation :: new ( & map) ;
278+
279+ let mut metas = HashSet :: new ( ) ;
280+ metas. insert ( FileId :: new ( 2 ) ) ;
281+
282+ let result =
283+ rel. get_best_analysis_order ( & [ FileId :: new ( 1 ) , FileId :: new ( 2 ) , FileId :: new ( 3 ) ] , & metas) ;
284+
285+ // File 2 is meta and has no dependencies, should be first
286+ // File 3 has no dependencies but is not meta, should be second
287+ // File 1 depends on file 2, should be last
288+ assert_eq ! ( result[ 0 ] , FileId :: new( 2 ) , "meta file should be first" ) ;
289+ assert_eq ! (
290+ result[ 1 ] ,
291+ FileId :: new( 3 ) ,
292+ "non-meta file with no dependencies should be second"
293+ ) ;
294+ assert_eq ! (
295+ result[ 2 ] ,
296+ FileId :: new( 1 ) ,
297+ "file with dependencies should be last"
298+ ) ;
299+ }
193300}
0 commit comments