@@ -44,11 +44,13 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
4444 }
4545
4646 fn sources_overlap_dests ( & self ) -> bool {
47- // Assumes `parallel_moves` has already been sorted in `resolve()` below.
48- for & ( _, dst, _) in & self . parallel_moves {
47+ // Assumes `parallel_moves` has already been sorted by `dst`
48+ // in `resolve()` below. The O(n log n) cost of this loop is no
49+ // worse than the sort we already did.
50+ for & ( src, _, _) in & self . parallel_moves {
4951 if self
5052 . parallel_moves
51- . binary_search_by_key ( & dst , |& ( src , _ , _) | src )
53+ . binary_search_by_key ( & src , |& ( _ , dst , _) | dst )
5254 . is_ok ( )
5355 {
5456 return true ;
@@ -75,16 +77,17 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
7577 return MoveVecWithScratch :: NoScratch ( self . parallel_moves ) ;
7678 }
7779
78- // Sort moves by source so that we can efficiently test for
79- // presence.
80+ // Sort moves so that we can efficiently test for presence.
81+ // For that purpose it doesn't matter whether we sort by
82+ // source or destination, but later we'll want them sorted
83+ // by destination.
8084 self . parallel_moves
81- . sort_by_key ( |& ( src, dst, _) | u64_key ( src . bits ( ) , dst . bits ( ) ) ) ;
85+ . sort_by_key ( |& ( src, dst, _) | u64_key ( dst . bits ( ) , src . bits ( ) ) ) ;
8286
83- // Do any dests overlap sources? If not, we can also just
84- // return the list.
85- if !self . sources_overlap_dests ( ) {
86- return MoveVecWithScratch :: NoScratch ( self . parallel_moves ) ;
87- }
87+ // Duplicate moves cannot change the semantics of this
88+ // parallel move set, so remove them. This is cheap since we
89+ // just sorted the list.
90+ self . parallel_moves . dedup ( ) ;
8891
8992 // General case: some moves overwrite dests that other moves
9093 // read as sources. We'll use a general algorithm.
@@ -102,10 +105,7 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
102105 // know we have the full cycle and we can do a cyclic move
103106 // sequence and continue.
104107
105- // Sort moves by destination and check that each destination
106- // has only one writer.
107- self . parallel_moves . sort_by_key ( |& ( _, dst, _) | dst) ;
108- self . parallel_moves . dedup ( ) ;
108+ // Check that each destination has only one writer.
109109 if cfg ! ( debug_assertions) {
110110 let mut last_dst = None ;
111111 for & ( _, dst, _) in & self . parallel_moves {
@@ -121,6 +121,12 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
121121 // into that destination.
122122 self . parallel_moves . retain ( |& mut ( src, dst, _) | src != dst) ;
123123
124+ // Do any dests overlap sources? If not, we can also just
125+ // return the list.
126+ if !self . sources_overlap_dests ( ) {
127+ return MoveVecWithScratch :: NoScratch ( self . parallel_moves ) ;
128+ }
129+
124130 // Construct a mapping from move indices to moves they must
125131 // come before. Any given move must come before a move that
126132 // overwrites its destination; we have moves sorted by dest
0 commit comments