@@ -44,11 +44,13 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
44
44
}
45
45
46
46
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 {
49
51
if self
50
52
. parallel_moves
51
- . binary_search_by_key ( & dst , |& ( src , _ , _) | src )
53
+ . binary_search_by_key ( & src , |& ( _ , dst , _) | dst )
52
54
. is_ok ( )
53
55
{
54
56
return true ;
@@ -75,16 +77,17 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
75
77
return MoveVecWithScratch :: NoScratch ( self . parallel_moves ) ;
76
78
}
77
79
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.
80
84
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 ( ) ) ) ;
82
86
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 ( ) ;
88
91
89
92
// General case: some moves overwrite dests that other moves
90
93
// read as sources. We'll use a general algorithm.
@@ -102,10 +105,7 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
102
105
// know we have the full cycle and we can do a cyclic move
103
106
// sequence and continue.
104
107
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.
109
109
if cfg ! ( debug_assertions) {
110
110
let mut last_dst = None ;
111
111
for & ( _, dst, _) in & self . parallel_moves {
@@ -121,6 +121,12 @@ impl<T: Clone + Copy + Default + PartialEq> ParallelMoves<T> {
121
121
// into that destination.
122
122
self . parallel_moves . retain ( |& mut ( src, dst, _) | src != dst) ;
123
123
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
+
124
130
// Construct a mapping from move indices to moves they must
125
131
// come before. Any given move must come before a move that
126
132
// overwrites its destination; we have moves sorted by dest
0 commit comments