@@ -153,6 +153,34 @@ impl Appendable for PartialPath {
153153 }
154154}
155155
156+ //-------------------------------------------------------------------------------------------------
157+ // Candidates
158+
159+ pub trait Candidates < H > {
160+ fn find_candidates < R > (
161+ & mut self ,
162+ graph : & StackGraph ,
163+ partials : & mut PartialPaths ,
164+ path : & PartialPath ,
165+ result : & mut R ,
166+ ) where
167+ R : std:: iter:: Extend < H > ;
168+ }
169+
170+ impl Candidates < Edge > for ( ) {
171+ fn find_candidates < R > (
172+ & mut self ,
173+ graph : & StackGraph ,
174+ _partials : & mut PartialPaths ,
175+ path : & PartialPath ,
176+ result : & mut R ,
177+ ) where
178+ R : std:: iter:: Extend < Edge > ,
179+ {
180+ result. extend ( graph. outgoing_edges ( path. end_node ) ) ;
181+ }
182+ }
183+
156184//-------------------------------------------------------------------------------------------------
157185// Databases
158186
@@ -420,6 +448,31 @@ impl Index<Handle<PartialPath>> for Database {
420448 }
421449}
422450
451+ impl Candidates < Handle < PartialPath > > for Database {
452+ fn find_candidates < R > (
453+ & mut self ,
454+ graph : & StackGraph ,
455+ partials : & mut PartialPaths ,
456+ path : & PartialPath ,
457+ result : & mut R ,
458+ ) where
459+ R : std:: iter:: Extend < Handle < PartialPath > > ,
460+ {
461+ if graph[ path. end_node ] . is_root ( ) {
462+ // The join node is root, so there's no need to use half-open symbol stacks here, as we
463+ // do for [`PartialPath::concatenate`][].
464+ let key = SymbolStackKey :: from_partial_symbol_stack (
465+ partials,
466+ self ,
467+ path. symbol_stack_postcondition ,
468+ ) ;
469+ self . find_candidate_partial_paths_from_root ( graph, partials, Some ( key) , result) ;
470+ } else {
471+ self . find_candidate_partial_paths_from_node ( graph, partials, path. end_node , result) ;
472+ }
473+ }
474+ }
475+
423476/// The key type that we use to find partial paths that start from the root node and have a
424477/// particular symbol stack as their precondition.
425478#[ derive( Clone , Copy ) ]
@@ -553,30 +606,23 @@ impl<'a> Display for DisplaySymbolStackKey<'a> {
553606/// completion, using the [`find_all_complete_partial_paths`][] method.
554607///
555608/// [`find_all_complete_partial_paths`]: #method.find_all_complete_partial_paths
556- pub struct ForwardPartialPathStitcher {
557- candidate_partial_paths : Vec < Handle < PartialPath > > ,
558- queue : VecDeque < ( PartialPath , AppendingCycleDetector < Handle < PartialPath > > ) > ,
609+ pub struct ForwardPartialPathStitcher < H > {
610+ candidates : Vec < H > ,
611+ queue : VecDeque < ( PartialPath , AppendingCycleDetector < H > ) > ,
559612 // next_iteration is a tuple of queues instead of an queue of tuples so that the path queue
560613 // can be cheaply exposed through the C API as a continuous memory block
561- next_iteration : (
562- VecDeque < PartialPath > ,
563- VecDeque < AppendingCycleDetector < Handle < PartialPath > > > ,
564- ) ,
565- appended_paths : Appendables < Handle < PartialPath > > ,
614+ next_iteration : ( VecDeque < PartialPath > , VecDeque < AppendingCycleDetector < H > > ) ,
615+ appended_paths : Appendables < H > ,
566616 similar_path_detector : Option < SimilarPathDetector < PartialPath > > ,
567617 max_work_per_phase : usize ,
568618 #[ cfg( feature = "copious-debugging" ) ]
569619 phase_number : usize ,
570620}
571621
572- impl ForwardPartialPathStitcher {
622+ impl < H > ForwardPartialPathStitcher < H > {
573623 /// Creates a new forward partial path stitcher that is "seeded" with a set of starting stack
574624 /// graph nodes.
575- pub fn from_nodes < I > (
576- graph : & StackGraph ,
577- partials : & mut PartialPaths ,
578- starting_nodes : I ,
579- ) -> ForwardPartialPathStitcher
625+ pub fn from_nodes < I > ( graph : & StackGraph , partials : & mut PartialPaths , starting_nodes : I ) -> Self
580626 where
581627 I : IntoIterator < Item = Handle < Node > > ,
582628 {
@@ -590,8 +636,8 @@ impl ForwardPartialPathStitcher {
590636 ( p, c)
591637 } )
592638 . unzip ( ) ;
593- ForwardPartialPathStitcher {
594- candidate_partial_paths : Vec :: new ( ) ,
639+ Self {
640+ candidates : Vec :: new ( ) ,
595641 queue : VecDeque :: new ( ) ,
596642 next_iteration,
597643 appended_paths,
@@ -609,7 +655,7 @@ impl ForwardPartialPathStitcher {
609655 _graph : & StackGraph ,
610656 partials : & mut PartialPaths ,
611657 initial_partial_paths : Vec < PartialPath > ,
612- ) -> ForwardPartialPathStitcher {
658+ ) -> Self {
613659 let mut appended_paths = Appendables :: new ( ) ;
614660 let next_iteration = initial_partial_paths
615661 . into_iter ( )
@@ -619,8 +665,8 @@ impl ForwardPartialPathStitcher {
619665 ( p, c)
620666 } )
621667 . unzip ( ) ;
622- ForwardPartialPathStitcher {
623- candidate_partial_paths : Vec :: new ( ) ,
668+ Self {
669+ candidates : Vec :: new ( ) ,
624670 queue : VecDeque :: new ( ) ,
625671 next_iteration,
626672 appended_paths,
@@ -631,7 +677,9 @@ impl ForwardPartialPathStitcher {
631677 phase_number : 1 ,
632678 }
633679 }
680+ }
634681
682+ impl < H : Clone > ForwardPartialPathStitcher < H > {
635683 /// Returns an iterator of all of the (possibly incomplete) partial paths that were encountered
636684 /// during the most recent phase of the algorithm.
637685 pub fn previous_phase_partial_paths ( & self ) -> impl Iterator < Item = & PartialPath > + ' _ {
@@ -676,60 +724,41 @@ impl ForwardPartialPathStitcher {
676724 /// Attempts to extend one partial path as part of the algorithm. When calling this function,
677725 /// you are responsible for ensuring that `db` already contains all of the possible partial
678726 /// paths that we might want to extend `partial_path` with.
679- fn stitch_partial_path (
727+ fn stitch_partial_path < ' a , A , Db > (
680728 & mut self ,
681729 graph : & StackGraph ,
682730 partials : & mut PartialPaths ,
683- db : & mut Database ,
731+ db : & mut Db ,
684732 partial_path : & PartialPath ,
685- cycle_detector : AppendingCycleDetector < Handle < PartialPath > > ,
686- ) -> usize {
687- self . candidate_partial_paths . clear ( ) ;
688- if graph[ partial_path. end_node ] . is_root ( ) {
689- // The join node is root, so there's no need to use half-open symbol stacks here, as we
690- // do for [`PartialPath::concatenate`][].
691- let key = SymbolStackKey :: from_partial_symbol_stack (
692- partials,
693- db,
694- partial_path. symbol_stack_postcondition ,
695- ) ;
696- db. find_candidate_partial_paths_from_root (
697- graph,
698- partials,
699- Some ( key) ,
700- & mut self . candidate_partial_paths ,
701- ) ;
702- } else {
703- db. find_candidate_partial_paths_from_node (
704- graph,
705- partials,
706- partial_path. end_node ,
707- & mut self . candidate_partial_paths ,
708- ) ;
709- }
733+ cycle_detector : AppendingCycleDetector < H > ,
734+ ) -> usize
735+ where
736+ A : Appendable + Clone + ' a ,
737+ Db : Candidates < H > + crate :: cycles:: Index < H , A > ,
738+ {
739+ self . candidates . clear ( ) ;
740+ db. find_candidates ( graph, partials, partial_path, & mut self . candidates ) ;
710741
711- let extension_count = self . candidate_partial_paths . len ( ) ;
742+ let extension_count = self . candidates . len ( ) ;
712743 self . next_iteration . 0 . reserve ( extension_count) ;
713744 self . next_iteration . 1 . reserve ( extension_count) ;
714- for extension in & self . candidate_partial_paths {
715- let mut extension_path = db[ * extension ] . clone ( ) ;
745+ for extension in & self . candidates {
746+ let extension_path = db. get ( extension ) ;
716747 copious_debugging ! ( " Extend {}" , partial_path. display( graph, partials) ) ;
717748 copious_debugging ! ( " with {}" , extension_path. display( graph, partials) ) ;
718- extension_path. ensure_no_overlapping_variables ( partials, partial_path) ;
719- copious_debugging ! ( " -> {}" , extension_path. display( graph, partials) ) ;
720749
721750 let mut new_partial_path = partial_path. clone ( ) ;
722751 let mut new_cycle_detector = cycle_detector. clone ( ) ;
723752 // If there are errors concatenating these partial paths, or resolving the resulting
724753 // partial path, just skip the extension — it's not a fatal error.
725754 #[ cfg_attr( not( feature = "copious-debugging" ) , allow( unused_variables) ) ]
726755 {
727- if let Err ( err) = new_partial_path . concatenate ( graph, partials, & extension_path ) {
756+ if let Err ( err) = extension_path . append_to ( graph, partials, & mut new_partial_path ) {
728757 copious_debugging ! ( " is invalid: {:?}" , err) ;
729758 continue ;
730759 }
731760 copious_debugging ! ( " is {}" , new_partial_path. display( graph, partials) ) ;
732- new_cycle_detector. append ( & mut self . appended_paths , * extension) ;
761+ new_cycle_detector. append ( & mut self . appended_paths , extension. clone ( ) ) ;
733762 let cycles = new_cycle_detector
734763 . is_cyclic ( graph, partials, db, & mut self . appended_paths )
735764 . expect ( "cyclic test failed when stitching partial paths" ) ;
@@ -773,12 +802,15 @@ impl ForwardPartialPathStitcher {
773802 /// list of the (possibly incomplete) partial paths that were encountered during this phase.
774803 ///
775804 /// [`previous_phase_partial_paths`]: #method.previous_phase_partial_paths
776- pub fn process_next_phase (
805+ pub fn process_next_phase < ' a , A , Db > (
777806 & mut self ,
778807 graph : & StackGraph ,
779808 partials : & mut PartialPaths ,
780- db : & mut Database ,
781- ) {
809+ db : & mut Db ,
810+ ) where
811+ A : Appendable + Clone + ' a ,
812+ Db : Candidates < H > + crate :: cycles:: Index < H , A > ,
813+ {
782814 copious_debugging ! ( "==> Start phase {}" , self . phase_number) ;
783815 self . queue . extend (
784816 self . next_iteration
@@ -811,7 +843,9 @@ impl ForwardPartialPathStitcher {
811843 self . phase_number += 1 ;
812844 }
813845 }
846+ }
814847
848+ impl < H > ForwardPartialPathStitcher < H > {
815849 /// Returns all of the complete partial paths that are reachable from a set of starting nodes,
816850 /// building them up by stitching together partial paths from this database.
817851 ///
0 commit comments