github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/internal/diff/lcs/sequence.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package lcs 6 7 // This file defines the abstract sequence over which the LCS algorithm operates. 8 9 // sequences abstracts a pair of sequences, A and B. 10 type sequences interface { 11 lengths() (int, int) // len(A), len(B) 12 commonPrefixLen(ai, aj, bi, bj int) int // len(commonPrefix(A[ai:aj], B[bi:bj])) 13 commonSuffixLen(ai, aj, bi, bj int) int // len(commonSuffix(A[ai:aj], B[bi:bj])) 14 } 15 16 type stringSeqs struct{ a, b string } 17 18 func (s stringSeqs) lengths() (int, int) { return len(s.a), len(s.b) } 19 func (s stringSeqs) commonPrefixLen(ai, aj, bi, bj int) int { 20 return commonPrefixLenString(s.a[ai:aj], s.b[bi:bj]) 21 } 22 func (s stringSeqs) commonSuffixLen(ai, aj, bi, bj int) int { 23 return commonSuffixLenString(s.a[ai:aj], s.b[bi:bj]) 24 } 25 26 // The explicit capacity in s[i:j:j] leads to more efficient code. 27 28 type bytesSeqs struct{ a, b []byte } 29 30 func (s bytesSeqs) lengths() (int, int) { return len(s.a), len(s.b) } 31 func (s bytesSeqs) commonPrefixLen(ai, aj, bi, bj int) int { 32 return commonPrefixLenBytes(s.a[ai:aj:aj], s.b[bi:bj:bj]) 33 } 34 func (s bytesSeqs) commonSuffixLen(ai, aj, bi, bj int) int { 35 return commonSuffixLenBytes(s.a[ai:aj:aj], s.b[bi:bj:bj]) 36 } 37 38 type runesSeqs struct{ a, b []rune } 39 40 func (s runesSeqs) lengths() (int, int) { return len(s.a), len(s.b) } 41 func (s runesSeqs) commonPrefixLen(ai, aj, bi, bj int) int { 42 return commonPrefixLenRunes(s.a[ai:aj:aj], s.b[bi:bj:bj]) 43 } 44 func (s runesSeqs) commonSuffixLen(ai, aj, bi, bj int) int { 45 return commonSuffixLenRunes(s.a[ai:aj:aj], s.b[bi:bj:bj]) 46 } 47 48 // TODO(adonovan): optimize these functions using ideas from: 49 // - https://go.dev/cl/408116 common.go 50 // - https://go.dev/cl/421435 xor_generic.go 51 52 // TODO(adonovan): factor using generics when available, 53 // but measure performance impact. 54 55 // commonPrefixLen* returns the length of the common prefix of a[ai:aj] and b[bi:bj]. 56 func commonPrefixLenBytes(a, b []byte) int { 57 n := min(len(a), len(b)) 58 i := 0 59 for i < n && a[i] == b[i] { 60 i++ 61 } 62 return i 63 } 64 func commonPrefixLenRunes(a, b []rune) int { 65 n := min(len(a), len(b)) 66 i := 0 67 for i < n && a[i] == b[i] { 68 i++ 69 } 70 return i 71 } 72 func commonPrefixLenString(a, b string) int { 73 n := min(len(a), len(b)) 74 i := 0 75 for i < n && a[i] == b[i] { 76 i++ 77 } 78 return i 79 } 80 81 // commonSuffixLen* returns the length of the common suffix of a[ai:aj] and b[bi:bj]. 82 func commonSuffixLenBytes(a, b []byte) int { 83 n := min(len(a), len(b)) 84 i := 0 85 for i < n && a[len(a)-1-i] == b[len(b)-1-i] { 86 i++ 87 } 88 return i 89 } 90 func commonSuffixLenRunes(a, b []rune) int { 91 n := min(len(a), len(b)) 92 i := 0 93 for i < n && a[len(a)-1-i] == b[len(b)-1-i] { 94 i++ 95 } 96 return i 97 } 98 func commonSuffixLenString(a, b string) int { 99 n := min(len(a), len(b)) 100 i := 0 101 for i < n && a[len(a)-1-i] == b[len(b)-1-i] { 102 i++ 103 } 104 return i 105 } 106 107 func min(x, y int) int { 108 if x < y { 109 return x 110 } else { 111 return y 112 } 113 }