diff --git a/src/karaxdb/btree.nim b/src/karaxdb/btree.nim index 14e79ab..e64396f 100644 --- a/src/karaxdb/btree.nim +++ b/src/karaxdb/btree.nim @@ -73,17 +73,17 @@ proc `=~`(i: int; k: CmpKind): bool = of CmpKind.gt: i > 0 of CmpKind.neq: i != 0 -proc canPrune(i: int; k: CmpKind): bool = +proc follow(i: int; k: CmpKind): bool = case k of CmpKind.eq: - # we demand equality so if bigger, we can prune: - i > 0 + # we demand equality so if less than, follow it + i < 0 of CmpKind.le: - i > 0 - of CmpKind.lt: i >= 0 - of CmpKind.ge: i < 0 - of CmpKind.gt: i <= 0 - of CmpKind.neq: i != 0 + i <= 0 + of CmpKind.lt: i <= 0 + of CmpKind.ge: i >= 0 + of CmpKind.gt: i >= 0 + of CmpKind.neq: true proc startingPoint(x: Node; key: Key; kind: CmpKind): Cursor = if x.isInternal: @@ -95,22 +95,79 @@ proc startingPoint(x: Node; key: Key; kind: CmpKind): Cursor = let cmpRes = cmp(key, x.keys[j]) if cmpRes =~ kind: return Cursor(n: x, i: j) -proc dos(x: Node; key: Key; kind: CmpKind; withKey: proc(k: Key; v: Val)) = +proc dos(x: Node; kind: CmpKind; key: Key; withKey: proc(k: Key; v: Val)) = if not x.isInternal: - echo "came here" for j in 0 ..< x.m: - if cmp(key, x.keys[j]) =~ kind: - withKey(x.keys[j+1], x.vals[j]) + if cmp(x.keys[j], key) =~ kind: + withKey(x.keys[j], x.vals[j]) else: - for j in 0 ..< x.m-1: - let cmpRes = cmp(key, x.keys[j+1]) - echo "came here B ", canPrune(cmpRes, kind) - if not canPrune(cmpRes, kind): #cmpRes =~ kind: - dos(x.links[j], key, kind, withKey) - #if canPrune(cmpRes, kind): return - # XXX j+1==x.m case? + # we compute the range of links to follow first, before + # recursing: + var followA = 0 + var followB = -1 + case kind + of CmpKind.eq: + # want: key == 10 + # keys: 0 3 4 5 10 20 + # keys: 20 30 40 + for j in 1..x.m: + if j == x.m or cmp(key, x.keys[j]) < 0: + followA = j-1 + followB = j-1 + break + of CmpKind.le, CmpKind.lt: + # want: key <= 10 or key < 10 + # keys: 0 3 4 5 10 20 + # keys: 20 30 40 + # Case A: all keys are bigger: + if cmp(key, x.keys[1]) < 0: + # --> use the very first branch + followA = 0 + followB = 0 + else: + # Case B: all keys are smaller --> use all branches is covered too + # by this loop. + for j in 1..= 0: + if followB < 0: followA = j-1 + # if the keys are identical and we require 'lt', we know + # only the left branch is required: + followB = j - ord(kind == CmpKind.lt and cmpRes == 0) + else: + # it's already greater, all others are greater too: + break + of CmpKind.ge, CmpKind.gt: + # want: key >= 10 or key > 10 + # keys: 0 3 4 5 10 20 + # keys: 20 30 40 + # Case A: all keys are smaller: + if cmp(key, x.keys[x.m-1]) >= 0: + # --> use the very last branch + followA = x.m-1 + followB = x.m-1 + else: + # also covers case B: all keys are bigger --> use all branches + # we find the key that is bigger or equal to ours and from + # then on, follow every branch: + for j in 1..= 5" + dos(b1.root, CmpKind.ge, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v)) + echo " <= 5" + dos(b1.root, CmpKind.le, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v)) + + echo " == 5" + dos(b1.root, CmpKind.eq, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v)) + echo " < 5" + dos(b1.root, CmpKind.lt, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v)) + echo " > 5" + dos(b1.root, CmpKind.gt, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v)) main()