|
1 | 1 | use std::iter; |
2 | 2 |
|
3 | | -const HEADER_SIZE: usize = 16; |
| 3 | +const GAP: usize = 16; |
4 | 4 |
|
5 | 5 | pub fn get_diff<'a>( |
6 | 6 | new_page: &'a [u8], |
7 | 7 | old_page: &'a [u8], |
8 | 8 | ) -> impl Iterator<Item = (usize, &'a [u8])> + 'a { |
9 | | - let l = new_page.len(); |
10 | | - let o = old_page.len(); |
11 | | - |
12 | | - let mut offset = 0; |
13 | | - let mut offset_end = 0; |
14 | | - |
15 | | - old_page |
| 9 | + let iter = old_page |
16 | 10 | .iter() |
17 | 11 | .chain(iter::repeat::<&u8>(&0)) |
18 | 12 | .zip(new_page) |
19 | | - .enumerate() |
20 | | - .filter_map(move |(i, values)| { |
21 | | - if values.0 == values.1 { |
22 | | - // if this value matches and the previous one did not, we know we just passed the end of one or more |
23 | | - // values that didn't match. In that case, we note the position by setting `offset_end` to `i` |
24 | | - if i != 0 && ((i < o && new_page[i - 1] != old_page[i - 1]) || i >= o && new_page[i - 1] != 0) { |
25 | | - offset_end = i; |
26 | | - } |
27 | | - // if we're HEADER_SIZE past the last section that needs changing, or at the end, we need to return the last blob of changes |
28 | | - if offset != offset_end && (offset_end + HEADER_SIZE == i || (i == (l - 1) && offset_end + HEADER_SIZE > i)) |
29 | | - { |
30 | | - return Some((offset, &new_page[offset..offset_end])); |
31 | | - } |
32 | | - } else { |
33 | | - // if this value doesn't match but the previous one did, we know we're at the beginning of one or more |
34 | | - // values that don't match. we note the position by updating `offset` to `i`. |
35 | | - if i == 0 || ((i < o && new_page[i - 1] == old_page[i - 1]) || i >= o && new_page[i-1] == 0) { |
36 | | - if offset_end == 0 || offset_end + HEADER_SIZE < i { |
37 | | - offset = i; |
| 13 | + .map(|(&old, &new)| (old, new)) |
| 14 | + .enumerate(); |
| 15 | + |
| 16 | + Diff { |
| 17 | + iter, |
| 18 | + gap: GAP, |
| 19 | + range: None, |
| 20 | + } |
| 21 | + .map(|(start, end)| (start, &new_page[start..=end])) |
| 22 | +} |
| 23 | + |
| 24 | +pub struct Diff<I> { |
| 25 | + iter: I, |
| 26 | + gap: usize, |
| 27 | + range: Option<(usize, usize)>, |
| 28 | +} |
| 29 | + |
| 30 | +impl<I> Iterator for Diff<I> |
| 31 | +where |
| 32 | + I: Iterator<Item = (usize, (u8, u8))>, |
| 33 | +{ |
| 34 | + type Item = (usize, usize); |
| 35 | + fn next(&mut self) -> Option<Self::Item> { |
| 36 | + while let Some(item) = self.iter.next() { |
| 37 | + match item { |
| 38 | + (i, (old, new)) if old != new => { |
| 39 | + self.range = match self.range { |
| 40 | + None => Some((i, i)), |
| 41 | + Some((start, _)) => Some((start, i)), |
38 | 42 | } |
39 | 43 | } |
40 | | - // normally, we add the values that need to be changed as soon as we see a matching value again, but |
41 | | - // when we're on the last value that doesn't match, we need to have special handing to include it. |
42 | | - if i == (l - 1) { |
43 | | - return Some((offset, &new_page[offset..=i])); |
44 | | - } |
| 44 | + (i, _) => match self.range { |
| 45 | + Some((_, end)) if end + self.gap < i => { |
| 46 | + return self.range.take(); |
| 47 | + } |
| 48 | + _ => {} |
| 49 | + }, |
45 | 50 | } |
46 | | - None |
47 | | - }) |
| 51 | + } |
| 52 | + self.range.take() |
| 53 | + } |
48 | 54 | } |
49 | 55 |
|
50 | 56 | #[cfg(test)] |
|
0 commit comments