2929//! always use this particular heuristic, however! We reserve the right to change the heuristic at
3030//! any time.
3131
32- use std:: collections:: HashMap ;
33-
3432use enumset:: EnumSet ;
3533use smallvec:: SmallVec ;
34+ use std:: collections:: HashMap ;
3635
3736use crate :: arena:: Handle ;
3837use crate :: arena:: List ;
@@ -45,6 +44,7 @@ use crate::partial::PartialPath;
4544use crate :: partial:: PartialPaths ;
4645use crate :: paths:: Path ;
4746use crate :: paths:: PathResolutionError ;
47+ use crate :: paths:: Paths ;
4848use crate :: stitching:: Database ;
4949use crate :: stitching:: OwnedOrDatabasePath ;
5050
@@ -58,44 +58,48 @@ pub struct SimilarPathDetector<P> {
5858pub struct PathKey {
5959 start_node : Handle < Node > ,
6060 end_node : Handle < Node > ,
61+ symbol_stack_precondition_len : usize ,
62+ scope_stack_precondition_len : usize ,
63+ symbol_stack_postcondition_len : usize ,
64+ scope_stack_postcondition_len : usize ,
6165}
6266
6367#[ doc( hidden) ]
6468pub trait HasPathKey : Clone {
69+ type Arena ;
6570 fn key ( & self ) -> PathKey ;
66- fn is_shorter_than ( & self , other : & Self ) -> bool ;
6771}
6872
6973impl HasPathKey for Path {
74+ type Arena = Paths ;
75+
7076 fn key ( & self ) -> PathKey {
7177 PathKey {
7278 start_node : self . start_node ,
7379 end_node : self . end_node ,
80+ symbol_stack_precondition_len : 0 ,
81+ scope_stack_precondition_len : 0 ,
82+ symbol_stack_postcondition_len : self . symbol_stack . len ( ) ,
83+ scope_stack_postcondition_len : self . scope_stack . len ( ) ,
7484 }
7585 }
76-
77- fn is_shorter_than ( & self , other : & Self ) -> bool {
78- self . edges . len ( ) < other. edges . len ( ) && self . symbol_stack . len ( ) <= other. symbol_stack . len ( )
79- }
8086}
8187
8288impl HasPathKey for PartialPath {
89+ type Arena = PartialPaths ;
90+
8391 fn key ( & self ) -> PathKey {
8492 PathKey {
8593 start_node : self . start_node ,
8694 end_node : self . end_node ,
95+ symbol_stack_precondition_len : self . symbol_stack_precondition . len ( ) ,
96+ scope_stack_precondition_len : self . scope_stack_precondition . len ( ) ,
97+ symbol_stack_postcondition_len : self . symbol_stack_postcondition . len ( ) ,
98+ scope_stack_postcondition_len : self . scope_stack_postcondition . len ( ) ,
8799 }
88100 }
89-
90- fn is_shorter_than ( & self , other : & Self ) -> bool {
91- self . edges . len ( ) < other. edges . len ( )
92- && ( self . symbol_stack_precondition . len ( ) + self . symbol_stack_postcondition . len ( ) )
93- <= ( other. symbol_stack_precondition . len ( ) + other. symbol_stack_postcondition . len ( ) )
94- }
95101}
96102
97- const MAX_SIMILAR_PATH_COUNT : usize = 7 ;
98-
99103impl < P > SimilarPathDetector < P >
100104where
101105 P : HasPathKey ,
@@ -107,34 +111,35 @@ where
107111 }
108112 }
109113
110- /// Determines whether we should process this path during the path-finding algorithm. If our
111- /// heuristics decide that this path is a duplicate, or is "non-productive", then we return
112- /// `false`, and the path-finding algorithm will skip this path.
113- pub fn should_process_path < F > ( & mut self , path : & P , cmp : F ) -> bool
114+ /// Determines whether we should process this path during the path-finding algorithm. If we have seen
115+ /// a path with the same start and end node, and the same pre- and postcondition, then we return false.
116+ /// Otherwise, we return true.
117+ pub fn has_similar_path < Eq > (
118+ & mut self ,
119+ _graph : & StackGraph ,
120+ arena : & mut P :: Arena ,
121+ path : & P ,
122+ eq : Eq ,
123+ ) -> bool
114124 where
115- F : FnMut ( & P ) -> std :: cmp :: Ordering ,
125+ Eq : Fn ( & mut P :: Arena , & P , & P ) -> bool ,
116126 {
117127 let key = path. key ( ) ;
118- let paths_with_same_nodes = self . paths . entry ( key) . or_default ( ) ;
119- let index = match paths_with_same_nodes. binary_search_by ( cmp) {
120- // We've already seen this exact path before; no need to process it again.
121- Ok ( _) => return false ,
122- // Otherwise add it to the list.
123- Err ( index) => index,
124- } ;
125128
126- // Count how many paths we've already processed that have the same endpoints and are
127- // "shorter".
128- let similar_path_count = paths_with_same_nodes
129- . iter ( )
130- . filter ( |similar_path| similar_path. is_shorter_than ( path) )
131- . count ( ) ;
132- if similar_path_count > MAX_SIMILAR_PATH_COUNT {
133- return false ;
129+ let possibly_similar_paths = self . paths . entry ( key) . or_default ( ) ;
130+ for other_path in possibly_similar_paths. iter ( ) {
131+ if eq ( arena, path, other_path) {
132+ return true ;
133+ }
134134 }
135135
136- paths_with_same_nodes. insert ( index, path. clone ( ) ) ;
137- true
136+ possibly_similar_paths. push ( path. clone ( ) ) ;
137+ false
138+ }
139+
140+ #[ cfg( feature = "copious-debugging" ) ]
141+ pub fn max_bucket_size ( & self ) -> usize {
142+ self . paths . iter ( ) . map ( |b| b. 1 . len ( ) ) . max ( ) . unwrap_or ( 0 )
138143 }
139144}
140145
0 commit comments