chore(parser/diff): use generic
This commit is contained in:
parent
7e61f8ae7d
commit
f3a93a2097
|
@ -50,7 +50,7 @@ func isWhitespace(b byte) bool {
|
||||||
b == 0xA0
|
b == 0xA0
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatDiff(oldList []string, newList []string, ops []Op) string {
|
func formatDiff(oldList []string, newList []string, ops []Op[string]) string {
|
||||||
var result []string
|
var result []string
|
||||||
i, j := 0, 0
|
i, j := 0, 0
|
||||||
for _, op := range ops {
|
for _, op := range ops {
|
||||||
|
|
|
@ -11,21 +11,21 @@ const (
|
||||||
OpDelete
|
OpDelete
|
||||||
)
|
)
|
||||||
|
|
||||||
type Op struct {
|
type Op[T any] struct {
|
||||||
OpType OpType // Insert or delete, as above
|
OpType OpType // Insert or delete, as above
|
||||||
OldPos int // Position in the old list of item to be inserted or deleted
|
OldPos int // Position in the old list of item to be inserted or deleted
|
||||||
NewPos int // Position in the _new_ list of item to be inserted
|
NewPos int // Position in the _new_ list of item to be inserted
|
||||||
Elem any // Actual value to be inserted or deleted
|
Elem T // Actual value to be inserted or deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a minimal list of differences between 2 lists e and f
|
// Returns a minimal list of differences between 2 lists e and f
|
||||||
// requiring O(min(len(e),len(f))) space and O(min(len(e),len(f)) * D)
|
// requiring O(min(len(e),len(f))) space and O(min(len(e),len(f)) * D)
|
||||||
// worst-case execution time where D is the number of differences.
|
// worst-case execution time where D is the number of differences.
|
||||||
func myersDiff(e, f []any, equals func(any, any) bool) []Op {
|
func myersDiff[T any](e, f []T, equals func(T, T) bool) []Op[T] {
|
||||||
return diffInternal(e, f, equals, 0, 0)
|
return diffInternal(e, f, equals, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func diffInternal(e, f []any, equals func(any, any) bool, i, j int) []Op {
|
func diffInternal[T any](e, f []T, equals func(T, T) bool, i, j int) []Op[T] {
|
||||||
N := len(e)
|
N := len(e)
|
||||||
M := len(f)
|
M := len(f)
|
||||||
L := N + M
|
L := N + M
|
||||||
|
@ -88,26 +88,26 @@ func diffInternal(e, f []any, equals func(any, any) bool, i, j int) []Op {
|
||||||
case D > 1 || (x != u && y != v):
|
case D > 1 || (x != u && y != v):
|
||||||
return append(diffInternal(e[0:x], f[0:y], equals, i, j), diffInternal(e[u:N], f[v:M], equals, i+u, j+v)...)
|
return append(diffInternal(e[0:x], f[0:y], equals, i, j), diffInternal(e[u:N], f[v:M], equals, i+u, j+v)...)
|
||||||
case M > N:
|
case M > N:
|
||||||
return diffInternal(make([]any, 0), f[N:M], equals, i+N, j+N)
|
return diffInternal(make([]T, 0), f[N:M], equals, i+N, j+N)
|
||||||
case M < N:
|
case M < N:
|
||||||
return diffInternal(e[M:N], make([]any, 0), equals, i+M, j+M)
|
return diffInternal(e[M:N], make([]T, 0), equals, i+M, j+M)
|
||||||
default:
|
default:
|
||||||
return make([]Op, 0)
|
return make([]Op[T], 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case N > 0:
|
case N > 0:
|
||||||
res := make([]Op, N)
|
res := make([]Op[T], N)
|
||||||
for n := range N {
|
for n := range N {
|
||||||
res[n] = Op{OpDelete, i + n, -1, e[n]}
|
res[n] = Op[T]{OpDelete, i + n, -1, e[n]}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
default:
|
default:
|
||||||
res := make([]Op, M)
|
res := make([]Op[T], M)
|
||||||
for n := range M {
|
for n := range M {
|
||||||
res[n] = Op{OpInsert, i, j + n, f[n]}
|
res[n] = Op[T]{OpInsert, i, j + n, f[n]}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -127,15 +127,8 @@ func pyMod(x, y int) int {
|
||||||
// Let us map element in same way as in
|
// Let us map element in same way as in
|
||||||
|
|
||||||
// Convenient wrapper for string lists
|
// Convenient wrapper for string lists
|
||||||
func myersDiffStr(e, f []string, compareSpace bool) []Op {
|
func myersDiffStr(e, f []string, compareSpace bool) []Op[string] {
|
||||||
e1, f1 := make([]any, len(e)), make([]any, len(f))
|
return myersDiff[string](e, f, func(s1, s2 string) bool {
|
||||||
for i, ee := range e {
|
return compareStrings(s1, s2, compareSpace)
|
||||||
e1[i] = ee
|
|
||||||
}
|
|
||||||
for i, fe := range f {
|
|
||||||
f1[i] = fe
|
|
||||||
}
|
|
||||||
return myersDiff(e1, f1, func(s1, s2 any) bool {
|
|
||||||
return compareStrings(s1.(string), s2.(string), compareSpace)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
type TestCase struct {
|
type TestCase struct {
|
||||||
l1 []string
|
l1 []string
|
||||||
l2 []string
|
l2 []string
|
||||||
exp []Op
|
exp []Op[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiff(t *t.T) {
|
func TestDiff(t *t.T) {
|
||||||
|
@ -16,28 +16,28 @@ func TestDiff(t *t.T) {
|
||||||
B := "B"
|
B := "B"
|
||||||
C := "C"
|
C := "C"
|
||||||
testCases := []TestCase{
|
testCases := []TestCase{
|
||||||
{[]string{}, []string{}, []Op{}},
|
{[]string{}, []string{}, []Op[string]{}},
|
||||||
{[]string{}, []string{"foo"}, []Op{{OpInsert, 0, 0, "foo"}}},
|
{[]string{}, []string{"foo"}, []Op[string]{{OpInsert, 0, 0, "foo"}}},
|
||||||
{[]string{"foo"}, []string{}, []Op{{OpDelete, 0, -1, "foo"}}},
|
{[]string{"foo"}, []string{}, []Op[string]{{OpDelete, 0, -1, "foo"}}},
|
||||||
{[]string{"foo", "bar", "baz"}, []string{"foo", "bar", "baz"}, []Op{}},
|
{[]string{"foo", "bar", "baz"}, []string{"foo", "bar", "baz"}, []Op[string]{}},
|
||||||
{[]string{"foo", "bar", "baz"}, []string{"foo", "baz"}, []Op{{OpDelete, 1, -1, "bar"}}},
|
{[]string{"foo", "bar", "baz"}, []string{"foo", "baz"}, []Op[string]{{OpDelete, 1, -1, "bar"}}},
|
||||||
{[]string{"baz"}, []string{"foo", "baz"}, []Op{{OpInsert, 0, 0, "foo"}}},
|
{[]string{"baz"}, []string{"foo", "baz"}, []Op[string]{{OpInsert, 0, 0, "foo"}}},
|
||||||
{[]string{"bar", "baz"}, []string{"foo", "baz"}, []Op{{OpDelete, 0, -1, "bar"}, {OpInsert, 1, 0, "foo"}}},
|
{[]string{"bar", "baz"}, []string{"foo", "baz"}, []Op[string]{{OpDelete, 0, -1, "bar"}, {OpInsert, 1, 0, "foo"}}},
|
||||||
{[]string{"foo", "bar", "baz"}, []string{"foo", "bar"}, []Op{{OpDelete, 2, -1, "baz"}}},
|
{[]string{"foo", "bar", "baz"}, []string{"foo", "bar"}, []Op[string]{{OpDelete, 2, -1, "baz"}}},
|
||||||
{
|
{
|
||||||
[]string{A, B, C, A, B, B, A},
|
[]string{A, B, C, A, B, B, A},
|
||||||
[]string{C, B, A, B, A, C},
|
[]string{C, B, A, B, A, C},
|
||||||
[]Op{{OpDelete, 0, -1, A}, {OpInsert, 1, 0, C}, {OpDelete, 2, -1, C}, {OpDelete, 5, -1, B}, {OpInsert, 7, 5, C}},
|
[]Op[string]{{OpDelete, 0, -1, A}, {OpInsert, 1, 0, C}, {OpDelete, 2, -1, C}, {OpDelete, 5, -1, B}, {OpInsert, 7, 5, C}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{C, A, B, A, B, A, B, A, B, A, B, A, B, C},
|
[]string{C, A, B, A, B, A, B, A, B, A, B, A, B, C},
|
||||||
[]string{B, A, B, A, B, A, B, A, B, A, B, A, B, A},
|
[]string{B, A, B, A, B, A, B, A, B, A, B, A, B, A},
|
||||||
[]Op{{OpDelete, 0, -1, C}, {OpInsert, 1, 0, B}, {OpDelete, 13, -1, C}, {OpInsert, 14, 13, A}},
|
[]Op[string]{{OpDelete, 0, -1, C}, {OpInsert, 1, 0, B}, {OpDelete, 13, -1, C}, {OpInsert, 14, 13, A}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{B},
|
[]string{B},
|
||||||
[]string{A, B, C, B, A},
|
[]string{A, B, C, B, A},
|
||||||
[]Op{{OpInsert, 0, 0, A}, {OpInsert, 0, 1, B}, {OpInsert, 0, 2, C}, {OpInsert, 1, 4, A}},
|
[]Op[string]{{OpInsert, 0, 0, A}, {OpInsert, 0, 1, B}, {OpInsert, 0, 2, C}, {OpInsert, 1, 4, A}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, c := range testCases {
|
for _, c := range testCases {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user