1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 |
// Package diff compares two versions of a document at two levels: blocks
// (paragraphs, list items, code) and, inside a changed block, words.
package diff
// EditKind is the type of one run in an edit script.
type EditKind int
const (
Eq EditKind = iota
Del
Ins
)
// Edit is a run of the edit script: a[A0:A1] deleted, b[B0:B1] inserted, or
// a[A0:A1] == b[B0:B1] kept.
type Edit struct {
Kind EditKind
A0, A1, B0, B1 int
}
// maxD bounds the search. Two versions that differ in more than maxD
// elements get one big replacement instead of an expensive minimal script;
// nobody reads a minimal diff of a rewritten page anyway.
const maxD = 4000
// Myers returns a shortest edit script from a to b (Myers 1986, the greedy
// O(ND) forward search with trace back), as runs in order.
func Myers[T comparable](a, b []T) []Edit {
pre := 0
for pre < len(a) && pre < len(b) && a[pre] == b[pre] {
pre++
}
suf := 0
for suf < len(a)-pre && suf < len(b)-pre && a[len(a)-1-suf] == b[len(b)-1-suf] {
suf++
}
mid := middle(a[pre:len(a)-suf], b[pre:len(b)-suf])
var out []Edit
add := func(e Edit) {
if e.A0 == e.A1 && e.B0 == e.B1 {
return
}
if n := len(out); n > 0 && out[n-1].Kind == e.Kind && out[n-1].A1 == e.A0 && out[n-1].B1 == e.B0 {
out[n-1].A1, out[n-1].B1 = e.A1, e.B1
return
}
out = append(out, e)
}
add(Edit{Eq, 0, pre, 0, pre})
for _, e := range mid {
add(Edit{e.Kind, e.A0 + pre, e.A1 + pre, e.B0 + pre, e.B1 + pre})
}
add(Edit{Eq, len(a) - suf, len(a), len(b) - suf, len(b)})
return out
}
func middle[T comparable](a, b []T) []Edit {
n, m := len(a), len(b)
if n == 0 && m == 0 {
return nil
}
if n == 0 || m == 0 {
return replaceAll(n, m)
}
max := n + m
if max > maxD {
max = maxD
}
offset := max + 1
v := make([]int, 2*max+3)
var trace [][]int
for d := 0; d <= max; d++ {
trace = append(trace, append([]int(nil), v...))
for k := -d; k <= d; k += 2 {
var x int
if k == -d || (k != d && v[offset+k-1] < v[offset+k+1]) {
x = v[offset+k+1]
} else {
x = v[offset+k-1] + 1
}
y := x - k
for x < n && y < m && a[x] == b[y] {
x++
y++
}
v[offset+k] = x
if x >= n && y >= m {
return backtrack(trace, offset, n, m)
}
}
}
return replaceAll(n, m)
}
func backtrack(trace [][]int, offset, n, m int) []Edit {
var rev []Edit
x, y := n, m
for d := len(trace) - 1; d > 0; d-- {
v := trace[d]
k := x - y
var prevK int
if k == -d || (k != d && v[offset+k-1] < v[offset+k+1]) {
prevK = k + 1
} else {
prevK = k - 1
}
prevX := v[offset+prevK]
prevY := prevX - prevK
for x > prevX && y > prevY {
rev = append(rev, Edit{Eq, x - 1, x, y - 1, y})
x--
y--
}
if x == prevX {
rev = append(rev, Edit{Ins, x, x, y - 1, y})
} else {
rev = append(rev, Edit{Del, x - 1, x, y, y})
}
x, y = prevX, prevY
}
for x > 0 && y > 0 {
rev = append(rev, Edit{Eq, x - 1, x, y - 1, y})
x--
y--
}
out := make([]Edit, 0, len(rev))
for i := len(rev) - 1; i >= 0; i-- {
e := rev[i]
if n := len(out); n > 0 && out[n-1].Kind == e.Kind && out[n-1].A1 == e.A0 && out[n-1].B1 == e.B0 {
out[n-1].A1, out[n-1].B1 = e.A1, e.B1
continue
}
out = append(out, e)
}
return out
}
func replaceAll(n, m int) []Edit {
var out []Edit
if n > 0 {
out = append(out, Edit{Del, 0, n, 0, 0})
}
if m > 0 {
out = append(out, Edit{Ins, n, n, 0, m})
}
return out
}
|