forked from epiclabs-io/diff3
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmyersdiff.go
More file actions
126 lines (116 loc) · 2.99 KB
/
myersdiff.go
File metadata and controls
126 lines (116 loc) · 2.99 KB
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
package diff3
import (
"iter"
)
func middleSnake[T comparable](a []T, b []T) (int, int, int, int, int) {
n := len(a)
m := len(b)
maxD := (n + m + 1) / 2
delta := n - m
deltaIsOdd := delta%2 != 0
vSize := 2*min(m, n) + 2
vf := make([]int, vSize)
vb := make([]int, vSize)
offset := maxD + 1
vf[(1+offset)%vSize] = 0
vb[(1+offset)%vSize] = 0
for d := 0; d <= maxD; d++ {
for k := -(d - 2*max(0, d-m)); k <= d-2*max(0, d-n); k += 2 {
var x, y int
idxK := (k + offset) % vSize
idxKPlus1 := (k + 1 + offset) % vSize
idxKMinus1 := (k - 1 + offset) % vSize
if k == -d || (k != d && vf[idxKMinus1] < vf[idxKPlus1]) {
x = vf[idxKPlus1]
} else {
x = vf[idxKMinus1] + 1
}
y = x - k
xStart, yStart := x, y
for x < n && y < m && a[x] == b[y] {
x++
y++
}
vf[idxK] = x
if deltaIsOdd {
inverseK := -(k - delta)
if inverseK >= -(d-1) && inverseK <= (d-1) {
idxInverseK := (inverseK + offset) % vSize
if vb[idxInverseK] != -1 && vf[idxK]+vb[idxInverseK] >= n {
return xStart, yStart, x, y, 2*d - 1
}
}
}
}
for k := -(d - 2*max(0, d-m)); k <= d-2*max(0, d-n); k += 2 {
var x, y int
idxK := (k + offset) % vSize
idxKPlus1 := (k + 1 + offset) % vSize
idxKMinus1 := (k - 1 + offset) % vSize
if k == -d || (k != d && vb[idxKMinus1] < vb[idxKPlus1]) {
x = vb[idxKPlus1]
} else {
x = vb[idxKMinus1] + 1
}
y = x - k
xStartRev, yStartRev := x, y
for x < n && y < m && a[n-1-x] == b[m-1-y] {
x++
y++
}
vb[idxK] = x
if !deltaIsOdd {
inverseK := -(k - delta)
if inverseK >= -d && inverseK <= d {
idxInverseK := (inverseK + offset) % vSize
if vf[idxInverseK] != -1 && vb[idxK]+vf[idxInverseK] >= n {
return n - x, m - y, n - xStartRev, m - yStartRev, 2 * d
}
}
}
}
}
panic("unreachable")
}
func shortestEditScript[T comparable](a, b []T, currentX, currentY int) iter.Seq[*diffIndicesResult] {
n, m := len(a), len(b)
if n == 0 && m == 0 {
return func(yield func(*diffIndicesResult) bool) {}
} else if n == 0 || m == 0 {
return func(yield func(*diffIndicesResult) bool) {
yield(&diffIndicesResult{
file1: [2]int{currentX, n},
file2: [2]int{currentY, m},
})
}
}
x, y, u, v, d := middleSnake(a, b)
if d > 1 || (x != u && y != v) {
it1 := make(chan iter.Seq[*diffIndicesResult], 1)
go func() {
it1 <- shortestEditScript[T](a[:x], b[:y], currentX, currentY)
}()
it2 := make(chan iter.Seq[*diffIndicesResult], 1)
go func() {
it2 <- shortestEditScript[T](a[u:], b[v:], currentX+u, currentY+v)
}()
return func(yield func(*diffIndicesResult) bool) {
for diff := range <-it1 {
if !yield(diff) {
return
}
}
for diff := range <-it2 {
if !yield(diff) {
return
}
}
}
} else if m > n {
return shortestEditScript[T](a[n:], b[n:], currentX+n, currentY+n)
} else if n > m {
return shortestEditScript[T](a[m:], b[m:], currentX+m, currentY+m)
} else {
return func(yield func(*diffIndicesResult) bool) {}
}
}