make editdistance work with --styleCheck:error

This commit is contained in:
Araq 2019-07-10 18:58:59 +02:00
commit dc0bbba3fa

View file

@ -22,158 +22,158 @@ proc editDistance*(a, b: string): int {.noSideEffect.} =
return editDistance(b, a) return editDistance(b, a)
# strip common prefix # strip common prefix
var var
i_start = 0 ## The character starting index of the first rune in both strings ``a`` and ``b`` iStart = 0 ## The character starting index of the first rune in both strings ``a`` and ``b``
i_next_a = 0 iNextA = 0
i_next_b = 0 iNextB = 0
rune_a, rune_b: Rune runeA, runeB: Rune
len_runes_a = 0 ## The number of relevant runes in string ``a``. lenRunesA = 0 ## The number of relevant runes in string ``a``.
len_runes_b = 0 ## The number of relevant runes in string ``b``. lenRunesB = 0 ## The number of relevant runes in string ``b``.
block commonPrefix: block commonPrefix:
# ``a`` is the shorter string # ``a`` is the shorter string
while i_start < len(a): while iStart < len(a):
i_next_a = i_start iNextA = iStart
a.fastRuneAt(i_next_a, rune_a, doInc = true) a.fastRuneAt(iNextA, runeA, doInc = true)
i_next_b = i_start iNextB = iStart
b.fastRuneAt(i_next_b, rune_b, doInc = true) b.fastRuneAt(iNextB, runeB, doInc = true)
if rune_a != rune_b: if runeA != runeB:
inc(len_runes_a) inc(lenRunesA)
inc(len_runes_b) inc(lenRunesB)
break break
i_start = i_next_a iStart = iNextA
var var
# we know that we are either at the start of the strings # we know that we are either at the start of the strings
# or that the current value of rune_a is not equal to rune_b # or that the current value of runeA is not equal to runeB
# => start search for common suffix after the current rune (``i_next_*``) # => start search for common suffix after the current rune (``i_next_*``)
i_end_a = i_next_a ## The exclusive upper index bound of string ``a``. iEndA = iNextA ## The exclusive upper index bound of string ``a``.
i_end_b = i_next_b ## The exclusive upper index bound of string ``b``. iEndB = iNextB ## The exclusive upper index bound of string ``b``.
i_current_a = i_next_a iCurrentA = iNextA
i_current_b = i_next_b iCurrentB = iNextB
block commonSuffix: block commonSuffix:
var var
add_runes_a = 0 addRunesA = 0
add_runes_b = 0 addRunesB = 0
while i_current_a < len(a) and i_current_b < len(b): while iCurrentA < len(a) and iCurrentB < len(b):
i_next_a = i_current_a iNextA = iCurrentA
a.fastRuneAt(i_next_a, rune_a) a.fastRuneAt(iNextA, runeA)
i_next_b = i_current_b iNextB = iCurrentB
b.fastRuneAt(i_next_b, rune_b) b.fastRuneAt(iNextB, runeB)
inc(add_runes_a) inc(addRunesA)
inc(add_runes_b) inc(addRunesB)
if rune_a != rune_b: if runeA != runeB:
i_end_a = i_next_a iEndA = iNextA
i_end_b = i_next_b iEndB = iNextB
inc(len_runes_a, add_runes_a) inc(lenRunesA, addRunesA)
inc(len_runes_b, add_runes_b) inc(lenRunesB, addRunesB)
add_runes_a = 0 addRunesA = 0
add_runes_b = 0 addRunesB = 0
i_current_a = i_next_a iCurrentA = iNextA
i_current_b = i_next_b iCurrentB = iNextB
if i_current_a >= len(a): # ``a`` exhausted if iCurrentA >= len(a): # ``a`` exhausted
if i_current_b < len(b): # ``b`` not exhausted if iCurrentB < len(b): # ``b`` not exhausted
i_end_a = i_current_a iEndA = iCurrentA
i_end_b = i_current_b iEndB = iCurrentB
inc(len_runes_a, add_runes_a) inc(lenRunesA, addRunesA)
inc(len_runes_b, add_runes_b) inc(lenRunesB, addRunesB)
while true: while true:
b.fastRuneAt(i_end_b, rune_b) b.fastRuneAt(iEndB, runeB)
inc(len_runes_b) inc(lenRunesB)
if i_end_b >= len(b): break if iEndB >= len(b): break
elif i_current_b >= len(b): # ``b`` exhausted and ``a`` not exhausted elif iCurrentB >= len(b): # ``b`` exhausted and ``a`` not exhausted
i_end_a = i_current_a iEndA = iCurrentA
i_end_b = i_current_b iEndB = iCurrentB
inc(len_runes_a, add_runes_a) inc(lenRunesA, addRunesA)
inc(len_runes_b, add_runes_b) inc(lenRunesB, addRunesB)
while true: while true:
a.fastRuneAt(i_end_a, rune_a) a.fastRuneAt(iEndA, runeA)
inc(len_runes_a) inc(lenRunesA)
if i_end_a >= len(a): break if iEndA >= len(a): break
block specialCases: block specialCases:
# trivial cases: # trivial cases:
if len_runes_a == 0: return len_runes_b if lenRunesA == 0: return lenRunesB
if len_runes_b == 0: return len_runes_a if lenRunesB == 0: return lenRunesA
# another special case: # another special case:
if len_runes_a == 1: if lenRunesA == 1:
a.fastRuneAt(i_start, rune_a, doInc = false) a.fastRuneAt(iStart, runeA, doInc = false)
var i_current_b = i_start var iCurrentB = iStart
while i_current_b < i_end_b: while iCurrentB < iEndB:
b.fastRuneAt(i_current_b, rune_b, doInc = true) b.fastRuneAt(iCurrentB, runeB, doInc = true)
if rune_a == rune_b: return len_runes_b - 1 if runeA == runeB: return lenRunesB - 1
return len_runes_b return lenRunesB
# common case: # common case:
var var
len1 = len_runes_a + 1 len1 = lenRunesA + 1
len2 = len_runes_b + 1 len2 = lenRunesB + 1
row: seq[int] row: seq[int]
let half = len_runes_a div 2 let half = lenRunesA div 2
newSeq(row, len2) newSeq(row, len2)
var e = i_start + len2 - 1 # end marker var e = iStart + len2 - 1 # end marker
# initialize first row: # initialize first row:
for i in 1 .. (len2 - half - 1): row[i] = i for i in 1 .. (len2 - half - 1): row[i] = i
row[0] = len1 - half - 1 row[0] = len1 - half - 1
i_current_a = i_start iCurrentA = iStart
var var
char2p_i = -1 char2pI = -1
char2p_prev: int char2pPrev: int
for i in 1 .. (len1 - 1): for i in 1 .. (len1 - 1):
i_next_a = i_current_a iNextA = iCurrentA
a.fastRuneAt(i_next_a, rune_a) a.fastRuneAt(iNextA, runeA)
var var
char2p: int char2p: int
D, x: int diff, x: int
p: int p: int
if i >= (len1 - half): if i >= (len1 - half):
# skip the upper triangle: # skip the upper triangle:
let offset = i + half - len1 let offset = i + half - len1
if char2p_i == i: if char2pI == i:
b.fastRuneAt(char2p_prev, rune_b) b.fastRuneAt(char2pPrev, runeB)
char2p = char2p_prev char2p = char2pPrev
char2p_i = i + 1 char2pI = i + 1
else: else:
char2p = i_start char2p = iStart
for j in 0 ..< offset: for j in 0 ..< offset:
rune_b = b.runeAt(char2p) runeB = b.runeAt(char2p)
inc(char2p, rune_b.size) inc(char2p, runeB.size)
char2p_i = i + 1 char2pI = i + 1
char2p_prev = char2p char2pPrev = char2p
p = offset p = offset
rune_b = b.runeAt(char2p) runeB = b.runeAt(char2p)
var c3 = row[p] + (if rune_a != rune_b: 1 else: 0) var c3 = row[p] + (if runeA != runeB: 1 else: 0)
inc(char2p, rune_b.size) inc(char2p, runeB.size)
inc(p) inc(p)
x = row[p] + 1 x = row[p] + 1
D = x diff = x
if x > c3: x = c3 if x > c3: x = c3
row[p] = x row[p] = x
inc(p) inc(p)
else: else:
p = 1 p = 1
char2p = i_start char2p = iStart
D = i diff = i
x = i x = i
if i <= (half + 1): if i <= (half + 1):
# skip the lower triangle: # skip the lower triangle:
e = len2 + i - half - 2 e = len2 + i - half - 2
# main: # main:
while p <= e: while p <= e:
dec(D) dec(diff)
rune_b = b.runeAt(char2p) runeB = b.runeAt(char2p)
var c3 = D + (if rune_a != rune_b: 1 else: 0) var c3 = diff + (if runeA != runeB: 1 else: 0)
inc(char2p, rune_b.size) inc(char2p, runeB.size)
inc(x) inc(x)
if x > c3: x = c3 if x > c3: x = c3
D = row[p] + 1 diff = row[p] + 1
if x > D: x = D if x > diff: x = diff
row[p] = x row[p] = x
inc(p) inc(p)
# lower triangle sentinel: # lower triangle sentinel:
if i <= half: if i <= half:
dec(D) dec(diff)
rune_b = b.runeAt(char2p) runeB = b.runeAt(char2p)
var c3 = D + (if rune_a != rune_b: 1 else: 0) var c3 = diff + (if runeA != runeB: 1 else: 0)
inc(x) inc(x)
if x > c3: x = c3 if x > c3: x = c3
row[p] = x row[p] = x
i_current_a = i_next_a iCurrentA = iNextA
result = row[e] result = row[e]
proc editDistanceAscii*(a, b: string): int {.noSideEffect.} = proc editDistanceAscii*(a, b: string): int {.noSideEffect.} =
@ -220,7 +220,7 @@ proc editDistanceAscii*(a, b: string): int {.noSideEffect.} =
for i in 1 .. len1 - 1: for i in 1 .. len1 - 1:
var char1 = a[i + s - 1] var char1 = a[i + s - 1]
var char2p: int var char2p: int
var D, x: int var diff, x: int
var p: int var p: int
if i >= len1 - half: if i >= len1 - half:
# skip the upper triangle: # skip the upper triangle:
@ -231,33 +231,33 @@ proc editDistanceAscii*(a, b: string): int {.noSideEffect.} =
inc(p) inc(p)
inc(char2p) inc(char2p)
x = row[p] + 1 x = row[p] + 1
D = x diff = x
if x > c3: x = c3 if x > c3: x = c3
row[p] = x row[p] = x
inc(p) inc(p)
else: else:
p = 1 p = 1
char2p = 0 char2p = 0
D = i diff = i
x = i x = i
if i <= half + 1: if i <= half + 1:
# skip the lower triangle: # skip the lower triangle:
e = len2 + i - half - 2 e = len2 + i - half - 2
# main: # main:
while p <= e: while p <= e:
dec(D) dec(diff)
var c3 = D + ord(char1 != b[char2p + s]) var c3 = diff + ord(char1 != b[char2p + s])
inc(char2p) inc(char2p)
inc(x) inc(x)
if x > c3: x = c3 if x > c3: x = c3
D = row[p] + 1 diff = row[p] + 1
if x > D: x = D if x > diff: x = diff
row[p] = x row[p] = x
inc(p) inc(p)
# lower triangle sentinel: # lower triangle sentinel:
if i <= half: if i <= half:
dec(D) dec(diff)
var c3 = D + ord(char1 != b[char2p + s]) var c3 = diff + ord(char1 != b[char2p + s])
inc(x) inc(x)
if x > c3: x = c3 if x > c3: x = c3
row[p] = x row[p] = x