@@ -37,49 +37,40 @@ pub fn consolidate_from<T: Ord, R: Semigroup>(vec: &mut Vec<(T, R)>, offset: usi
37
37
/// Sorts and consolidates a slice, returning the valid prefix length.
38
38
pub fn consolidate_slice < T : Ord , R : Semigroup > ( slice : & mut [ ( T , R ) ] ) -> usize {
39
39
40
- // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
41
- // In a world where there are not many results, we may never even need to call in to merge sort.
42
- slice. sort_by ( |x, y| x. 0 . cmp ( & y. 0 ) ) ;
43
-
44
- let slice_ptr = slice. as_mut_ptr ( ) ;
45
-
46
- // Counts the number of distinct known-non-zero accumulations. Indexes the write location.
47
- let mut offset = 0 ;
48
- for index in 1 .. slice. len ( ) {
49
-
50
- // The following unsafe block elides various bounds checks, using the reasoning that `offset`
51
- // is always strictly less than `index` at the beginning of each iteration. This is initially
52
- // true, and in each iteration `offset` can increase by at most one (whereas `index` always
53
- // increases by one). As `index` is always in bounds, and `offset` starts at zero, it too is
54
- // always in bounds.
55
- //
56
- // LLVM appears to struggle to optimize out Rust's split_at_mut, which would prove disjointness
57
- // using run-time tests.
58
- unsafe {
59
-
60
- assert ! ( offset < index) ;
61
-
62
- // LOOP INVARIANT: offset < index
63
- let ptr1 = slice_ptr. add ( offset) ;
64
- let ptr2 = slice_ptr. add ( index) ;
65
-
66
- if ( * ptr1) . 0 == ( * ptr2) . 0 {
67
- ( * ptr1) . 1 . plus_equals ( & ( * ptr2) . 1 ) ;
40
+ if slice. len ( ) > 1 {
41
+
42
+ // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
43
+ // In a world where there are not many results, we may never even need to call in to merge sort.
44
+ slice. sort_by ( |x, y| x. 0 . cmp ( & y. 0 ) ) ;
45
+
46
+ // Counts the number of distinct known-non-zero accumulations. Indexes the write location.
47
+ let mut offset = 0 ;
48
+ let mut accum = slice[ offset] . 1 . clone ( ) ;
49
+
50
+ for index in 1 .. slice. len ( ) {
51
+ if slice[ index] . 0 == slice[ index-1 ] . 0 {
52
+ accum. plus_equals ( & slice[ index] . 1 ) ;
68
53
}
69
54
else {
70
- if !( * ptr1) . 1 . is_zero ( ) {
55
+ if !accum. is_zero ( ) {
56
+ slice. swap ( offset, index-1 ) ;
57
+ slice[ offset] . 1 . clone_from ( & accum) ;
71
58
offset += 1 ;
72
59
}
73
- let ptr1 = slice_ptr. add ( offset) ;
74
- std:: ptr:: swap ( ptr1, ptr2) ;
60
+ accum. clone_from ( & slice[ index] . 1 ) ;
75
61
}
76
62
}
63
+ if !accum. is_zero ( ) {
64
+ slice. swap ( offset, slice. len ( ) -1 ) ;
65
+ slice[ offset] . 1 = accum;
66
+ offset += 1 ;
67
+ }
68
+
69
+ offset
77
70
}
78
- if offset < slice . len ( ) && !slice [ offset ] . 1 . is_zero ( ) {
79
- offset += 1 ;
71
+ else {
72
+ slice . iter ( ) . filter ( |x| !x . 1 . is_zero ( ) ) . count ( )
80
73
}
81
-
82
- offset
83
74
}
84
75
85
76
/// Sorts and consolidates `vec`.
@@ -104,50 +95,43 @@ pub fn consolidate_updates_from<D: Ord, T: Ord, R: Semigroup>(vec: &mut Vec<(D,
104
95
/// Sorts and consolidates a slice, returning the valid prefix length.
105
96
pub fn consolidate_updates_slice < D : Ord , T : Ord , R : Semigroup > ( slice : & mut [ ( D , T , R ) ] ) -> usize {
106
97
107
- // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs.
108
- // In a world where there are not many results, we may never even need to call in to merge sort.
109
- slice. sort_unstable_by ( |x, y| ( & x. 0 , & x. 1 ) . cmp ( & ( & y. 0 , & y. 1 ) ) ) ;
110
-
111
- let slice_ptr = slice. as_mut_ptr ( ) ;
98
+ if slice. len ( ) > 1 {
112
99
113
- // Counts the number of distinct known-non-zero accumulations. Indexes the write location .
114
- let mut offset = 0 ;
115
- for index in 1 .. slice . len ( ) {
100
+ // We could do an insertion-sort like initial scan which builds up sorted, consolidated runs .
101
+ // In a world where there are not many results, we may never even need to call in to merge sort.
102
+ slice . sort_unstable_by ( |x , y| ( & x . 0 , & x . 1 ) . cmp ( & ( & y . 0 , & y . 1 ) ) ) ;
116
103
117
- // The following unsafe block elides various bounds checks, using the reasoning that `offset`
118
- // is always strictly less than `index` at the beginning of each iteration. This is initially
119
- // true, and in each iteration `offset` can increase by at most one (whereas `index` always
120
- // increases by one). As `index` is always in bounds, and `offset` starts at zero, it too is
121
- // always in bounds.
122
- //
123
- // LLVM appears to struggle to optimize out Rust's split_at_mut, which would prove disjointness
124
- // using run-time tests.
125
- unsafe {
104
+ // Counts the number of distinct known-non-zero accumulations. Indexes the write location.
105
+ let mut offset = 0 ;
106
+ let mut accum = slice[ offset] . 2 . clone ( ) ;
126
107
127
- // LOOP INVARIANT: offset < index
128
- let ptr1 = slice_ptr. add ( offset) ;
129
- let ptr2 = slice_ptr. add ( index) ;
130
-
131
- if ( * ptr1) . 0 == ( * ptr2) . 0 && ( * ptr1) . 1 == ( * ptr2) . 1 {
132
- ( * ptr1) . 2 . plus_equals ( & ( * ptr2) . 2 ) ;
108
+ for index in 1 .. slice. len ( ) {
109
+ if ( slice[ index] . 0 == slice[ index-1 ] . 0 ) && ( slice[ index] . 1 == slice[ index-1 ] . 1 ) {
110
+ accum. plus_equals ( & slice[ index] . 2 ) ;
133
111
}
134
112
else {
135
- if !( * ptr1) . 2 . is_zero ( ) {
113
+ if !accum. is_zero ( ) {
114
+ slice. swap ( offset, index-1 ) ;
115
+ slice[ offset] . 2 . clone_from ( & accum) ;
136
116
offset += 1 ;
137
117
}
138
- let ptr1 = slice_ptr. add ( offset) ;
139
- std:: ptr:: swap ( ptr1, ptr2) ;
118
+ accum. clone_from ( & slice[ index] . 2 ) ;
140
119
}
141
-
142
120
}
121
+ if !accum. is_zero ( ) {
122
+ slice. swap ( offset, slice. len ( ) -1 ) ;
123
+ slice[ offset] . 2 = accum;
124
+ offset += 1 ;
125
+ }
126
+
127
+ offset
143
128
}
144
- if offset < slice . len ( ) && !slice [ offset ] . 2 . is_zero ( ) {
145
- offset += 1 ;
129
+ else {
130
+ slice . iter ( ) . filter ( |x| !x . 2 . is_zero ( ) ) . count ( )
146
131
}
147
-
148
- offset
149
132
}
150
133
134
+
151
135
/// A container builder that consolidates data in-places into fixed-sized containers. Does not
152
136
/// maintain FIFO ordering.
153
137
#[ derive( Default ) ]
@@ -332,6 +316,6 @@ mod tests {
332
316
for i in 0 ..1024 {
333
317
assert_eq ! ( ( i, 0 , 2 ) , collected[ i] ) ;
334
318
}
335
-
319
+
336
320
}
337
321
}
0 commit comments