Fix empty LIS

This commit is contained in:
Roman Vishnevskii 2017-05-10 18:51:13 +07:00
commit e88f9e4c96
2 changed files with 28 additions and 9 deletions

View file

@ -1,6 +1,6 @@
## Karax -- Single page applications for Nim. ## Karax -- Single page applications for Nim.
import dom, vdom, jstrutils, components, jdict, tables import dom, vdom, jstrutils, components, jdict
export dom.Event export dom.Event
@ -184,6 +184,9 @@ proc print(s: cstring, ident: int) =
# kout cstring(result) # kout cstring(result)
proc longestIncreasingSubsequence(a: seq[int]): seq[int] = proc longestIncreasingSubsequence(a: seq[int]): seq[int] =
if len(a) == 0:
return @[]
result.add 0 result.add 0
var parent = newSeq[int](len(a)) var parent = newSeq[int](len(a))
for i in 0..<len(a): for i in 0..<len(a):
@ -216,6 +219,10 @@ proc longestIncreasingSubsequence(a: seq[int]): seq[int] =
dec pos dec pos
proc updateElement(parent, current: Node, newNode, oldNode: VNode, ident: int = 0) = proc updateElement(parent, current: Node, newNode, oldNode: VNode, ident: int = 0) =
if newNode.key != -1:
kout cstring($newNode.key)
if oldNode.key != -1:
kout cstring($oldNode.key)
newNode.dom = oldNode.dom newNode.dom = oldNode.dom
if not equalsShallow(newNode, oldNode): if not equalsShallow(newNode, oldNode):
detach(oldNode) detach(oldNode)
@ -317,6 +324,10 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode, ident: int =
if not isKeyed: if not isKeyed:
break break
if rightNew - leftNew + 1 + rightOld - leftOld + 1 == 0:
isKeyed = false
if isKeyed: if isKeyed:
if rightNew > leftNew: if rightNew > leftNew:
# remove redundant old nodes # remove redundant old nodes
@ -325,14 +336,22 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode, ident: int =
detach(oldNode[i]) detach(oldNode[i])
else: else:
# permute elements using LIS # permute elements using LIS
var positionByKey = newTable[VKey, int]() var positionByKey = newJDict[VKey, int]()
var positions = newSeq[int]() var positions = newSeq[int]()
for i in leftOld..rightOld: for i in leftOld..rightOld:
positionByKey[oldNode[i].key] = i positionByKey[oldNode[i].key] = i
for i in leftNew..rightNew: for i in leftNew..rightNew:
if positionByKey.hasKey(newNode[i].key): if positionByKey.contains(newNode[i].key):
positions.add positionByKey[newNode[i].key] positions.add positionByKey[newNode[i].key]
#if len(positions) > 0:
# kout cstring("new segment len = " & $(rightNew - leftNew + 1))
# kout cstring("old segment len = " & $(rightOld - leftOld + 1))
# var t = ""
# for i in 0..<len(positions):
# t.add($positions[i] & " ")
# kout cstring(t)
var lis = longestIncreasingSubsequence(positions) var lis = longestIncreasingSubsequence(positions)
var lisPos = 0 var lisPos = 0
var isNotRedundant = newSeq[bool](rightOld - leftOld + 1) var isNotRedundant = newSeq[bool](rightOld - leftOld + 1)
@ -344,14 +363,14 @@ proc updateElement(parent, current: Node, newNode, oldNode: VNode, ident: int =
updateElement(current, oldNode[index].dom, newNode[i], oldNode[index], ident + 1) updateElement(current, oldNode[index].dom, newNode[i], oldNode[index], ident + 1)
inc lisPos inc lisPos
else: else:
if positionByKey.hasKey(newNode[i].key): if positionByKey.contains(newNode[i].key):
var oldPos = positionByKey[newNode[i].key] var oldPos = positionByKey[newNode[i].key]
isNotRedundant[oldPos - leftOld] = true isNotRedundant[oldPos - leftOld] = true
current.insertBefore(oldNode[oldPos].dom, oldNode[index].dom) current.insertBefore(oldNode[oldPos].dom, oldNode[index].dom)
else: else:
current.insertBefore(vnodeToDom(newNode[i]), oldNode[index].dom) current.insertBefore(vnodeToDom(newNode[i]), oldNode[index].dom)
else: else:
if positionByKey.hasKey(newNode[i].key): if positionByKey.contains(newNode[i].key):
var oldPos = positionByKey[newNode[i].key] var oldPos = positionByKey[newNode[i].key]
isNotRedundant[oldPos - leftOld] = true isNotRedundant[oldPos - leftOld] = true
current.appendChild(oldNode[oldPos].dom) current.appendChild(oldNode[oldPos].dom)

View file

@ -83,16 +83,16 @@ proc test4() =
timeout = setTimeout(check4, 20) timeout = setTimeout(check4, 20)
proc check5() = proc check5() =
let result = checkOrder(@[0, 1, 3, 5, 4, 5]) let result = checkOrder(@[0, 1, 3, 5, 4, 8])
if result: if result:
results.add cstring"test5 - OK" results.add cstring"test5 - OK"
else: else:
results.add cstring"test5 - FAIL" results.add cstring"test5 - FAIL"
# result: 0 1 3 5 4 5 # result: 0 1 3 5 4 8
proc test5() = proc test5() =
results.add cstring"test5 started" results.add cstring"test5 started"
entries = @[cstring("0"), cstring("1"), cstring("3"), cstring("5"), cstring("4"), cstring("5") ] entries = @[cstring("0"), cstring("1"), cstring("3"), cstring("5"), cstring("4"), cstring("8") ]
redraw() redraw()
timeout = setTimeout(check5, 20) timeout = setTimeout(check5, 20)
@ -127,7 +127,7 @@ proc test7() =
proc createEntry(id: int): VNode = proc createEntry(id: int): VNode =
result = buildHtml(): result = buildHtml():
button(id="" & $id): button(id="" & $id, key = id):
text $id text $id
proc createDom(): VNode = proc createDom(): VNode =