Skip to content

Commit f285566

Browse files
authored
Merge pull request #25 from ltratt/filter_empty_values
Optimise by filtering out empty values.
2 parents d6077d2 + 6bca7f0 commit f285566

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/lib.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,26 @@ fn compress<T: Clone + Copy + PartialEq>(
174174
let mut r = Vec::new(); // Result vector
175175
r.resize(row_length, empty_val);
176176

177-
let mut dv = Vec::new(); // displacement vector
178-
dv.resize(sorted.len(), 0);
177+
let mut dv = vec![0; sorted.len()]; // displacement vector
179178

179+
let mut tmp = Vec::new();
180180
for s in sorted {
181-
let slice = &vec[s * row_length..(s + 1) * row_length];
181+
// The row we're about to iterate over typically contains mostly empty values that can
182+
// never succeed with `fits`. We pre-filter out all those empty values up-front, such that
183+
// `tmp` contains `(index, non-empty-value)` pairs that we can then pass to `fits`. Because
184+
// this is such a tight loop, we reuse the same `Vec` to avoid repeated allocations.
185+
tmp.clear();
186+
tmp.extend(
187+
vec[s * row_length..(s + 1) * row_length]
188+
.iter()
189+
.enumerate()
190+
.filter(|(_, v)| **v != empty_val),
191+
);
192+
182193
let mut d = 0; // displacement value
183194
loop {
184-
if fits(slice, &r, d, empty_val) {
185-
apply(slice, &mut r, d, empty_val);
195+
if fits(tmp.as_slice(), &r, d, empty_val) {
196+
apply(tmp.as_slice(), &mut r, d);
186197
dv[*s] = d;
187198
break;
188199
} else {
@@ -196,27 +207,24 @@ fn compress<T: Clone + Copy + PartialEq>(
196207
(r, dv)
197208
}
198209

199-
fn fits<T: PartialEq>(v: &[T], target: &[T], d: usize, empty_val: T) -> bool {
200-
for i in 0..v.len() {
201-
if v[i] != empty_val && target[d + i] != empty_val && target[d + i] != v[i] {
210+
/// `v` is an array of `(index, non-empty_val)` pairs.
211+
fn fits<T: PartialEq>(v: &[(usize, &T)], target: &[T], d: usize, empty_val: T) -> bool {
212+
for (i, x) in v {
213+
if target[d + i] != empty_val && target[d + i] != **x {
202214
return false;
203215
}
204216
}
205217
true
206218
}
207219

208-
fn apply<T: Copy + PartialEq>(v: &[T], target: &mut [T], d: usize, empty_val: T) {
209-
for i in 0..v.len() {
210-
if v[i] != empty_val {
211-
target[d + i] = v[i]
212-
}
220+
/// `v` is an array of `(index, non-empty_val)` pairs.
221+
fn apply<T: Copy + PartialEq>(v: &[(usize, &T)], target: &mut [T], d: usize) {
222+
for (i, x) in v {
223+
target[d + i] = **x;
213224
}
214225
}
215226

216-
fn sort<T: PartialEq>(v: &[T], empty_val: T, row_length: usize) -> Vec<usize>
217-
where
218-
T: PartialEq<T>,
219-
{
227+
fn sort<T: PartialEq>(v: &[T], empty_val: T, row_length: usize) -> Vec<usize> {
220228
let mut o: Vec<usize> = (0..v.len() / row_length).collect();
221229
o.sort_by_key(|x| {
222230
v[(x * row_length)..((x + 1) * row_length)]

0 commit comments

Comments
 (0)