MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / diff_tokens

Function diff_tokens

atomic-core/src/merge/three_way.rs:176–235  ·  view source on GitHub ↗

Compute an edit script transforming `old` into `new` at the token level. Returns a sequence of [`EditOp`]s. The algorithm uses dynamic-programming LCS to align the two sequences and then walks the DP table to emit keep / delete / insert / replace operations.

(old: &[MergeToken], new: &[MergeToken])

Source from the content-addressed store, hash-verified

174/// LCS to align the two sequences and then walks the DP table to emit
175/// keep / delete / insert / replace operations.
176fn diff_tokens(old: &[MergeToken], new: &[MergeToken]) -> Vec<EditOp> {
177 let n = old.len();
178 let m = new.len();
179
180 if n == 0 && m == 0 {
181 return Vec::new();
182 }
183 if n == 0 {
184 // Everything in `new` is an insertion before the start.
185 return new
186 .iter()
187 .map(|t| EditOp::Insert(usize::MAX, t.content.clone()))
188 .collect();
189 }
190 if m == 0 {
191 return (0..n).map(EditOp::Delete).collect();
192 }
193
194 // DP table for LCS lengths: dp[i][j] = LCS(old[0..i], new[0..j])
195 let mut dp = vec![vec![0u32; m + 1]; n + 1];
196 for i in 1..=n {
197 for j in 1..=m {
198 if old[i - 1] == new[j - 1] {
199 dp[i][j] = dp[i - 1][j - 1] + 1;
200 } else {
201 dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]);
202 }
203 }
204 }
205
206 // Back-track to produce edit operations.
207 let mut ops = Vec::new();
208 let mut i = n;
209 let mut j = m;
210
211 // We collect in reverse order, then reverse at the end.
212 while i > 0 || j > 0 {
213 if i > 0 && j > 0 && old[i - 1] == new[j - 1] {
214 ops.push(EditOp::Keep(i - 1));
215 i -= 1;
216 j -= 1;
217 } else if j > 0 && (i == 0 || dp[i][j - 1] >= dp[i - 1][j]) {
218 // Insertion from `new` — record the base index *after which* it sits.
219 let after = if i > 0 { i - 1 } else { usize::MAX };
220 ops.push(EditOp::Insert(after, new[j - 1].content.clone()));
221 j -= 1;
222 } else {
223 // Deletion from `old`.
224 ops.push(EditOp::Delete(i - 1));
225 i -= 1;
226 }
227 }
228
229 ops.reverse();
230
231 // Coalesce adjacent Delete(i) + Insert(i, _) into Replace(i, _).
232 coalesce_replace(&mut ops);
233

Callers 4

three_way_mergeFunction · 0.85
test_diff_tokens_all_newFunction · 0.85

Calls 8

InsertClass · 0.85
coalesce_replaceFunction · 0.85
DeleteClass · 0.50
lenMethod · 0.45
iterMethod · 0.45
cloneMethod · 0.45
pushMethod · 0.45
reverseMethod · 0.45

Tested by 3

test_diff_tokens_all_newFunction · 0.68