imara_diff/
util.rs

1use crate::intern::Token;
2use crate::Hunk;
3
4pub fn common_prefix(file1: &[Token], file2: &[Token]) -> u32 {
5    let mut off = 0;
6    for (token1, token2) in file1.iter().zip(file2) {
7        if token1 != token2 {
8            break;
9        }
10        off += 1;
11    }
12    off
13}
14
15pub fn common_postfix(file1: &[Token], file2: &[Token]) -> u32 {
16    let mut off = 0;
17    for (token1, token2) in file1.iter().rev().zip(file2.iter().rev()) {
18        if token1 != token2 {
19            break;
20        }
21        off += 1;
22    }
23    off
24}
25
26pub fn common_edges(file1: &[Token], file2: &[Token]) -> (u32, u32) {
27    let prefix = common_prefix(file1, file2);
28    let postfix = common_postfix(&file1[prefix as usize..], &file2[prefix as usize..]);
29    (prefix, postfix)
30}
31
32pub fn strip_common_prefix(file1: &mut &[Token], file2: &mut &[Token]) -> u32 {
33    let off = common_prefix(file1, file2);
34    *file1 = &file1[off as usize..];
35    *file2 = &file2[off as usize..];
36    off
37}
38
39pub fn strip_common_postfix(file1: &mut &[Token], file2: &mut &[Token]) -> u32 {
40    let off = common_postfix(file1, file2);
41    *file1 = &file1[..file1.len() - off as usize];
42    *file2 = &file2[..file2.len() - off as usize];
43    off
44}
45
46pub fn sqrt(val: usize) -> u32 {
47    let nbits = (usize::BITS - val.leading_zeros()) / 2;
48    1 << nbits
49}
50
51impl Hunk {
52    pub(crate) fn next_hunk(&mut self, removed: &[bool], added: &[bool]) -> bool {
53        let Some(off) = find_next_change(added, self.after.end) else {
54            return false;
55        };
56        let mut off_before = 0;
57        loop {
58            debug_assert!(
59                removed.len() as u32 != self.before.end || off == 0,
60                "broken hunk alignment {self:?} "
61            );
62            let unchanged_tokens = find_next_change(removed, self.before.end)
63                .unwrap_or(removed.len() as u32 - self.before.end);
64            if off_before + unchanged_tokens > off {
65                self.before.start = self.before.end + (off - off_before);
66                self.before.end = self.before.start;
67                break;
68            }
69            off_before += unchanged_tokens;
70            self.before.start = self.before.end + unchanged_tokens;
71            self.before.end = find_hunk_end(removed, self.before.end + unchanged_tokens);
72            if off_before == off {
73                break;
74            }
75        }
76        self.after.start = self.after.end + off;
77        self.after.end = find_hunk_end(added, self.after.start);
78        true
79    }
80}
81
82pub fn find_next_change(changes: &[bool], pos: u32) -> Option<u32> {
83    changes[pos as usize..]
84        .iter()
85        .position(|&changed| changed)
86        .map(|off| off as u32)
87}
88
89pub fn find_hunk_end(changes: &[bool], pos: u32) -> u32 {
90    pos + changes[pos as usize..]
91        .iter()
92        .take_while(|&&changed| changed)
93        .count() as u32
94}
95
96pub fn find_hunk_start(changes: &[bool], pos: u32) -> u32 {
97    pos - changes[..pos as usize]
98        .iter()
99        .rev()
100        .take_while(|&&changed| changed)
101        .count() as u32
102}