Commit d98ed0e1 authored by Kirill Smelkov's avatar Kirill Smelkov

X goodbye xkey

Reworked hitK* and associated set flags to liveseparately not to create
holes.
parent 8b1f6c22
......@@ -155,6 +155,32 @@ func opPut(written bool) treeOp {
return opGet
}
func xeq(k1, k2 interface{} /*K*/, k1set, k2set bool) bool {
if k1set != k2set {
return false
}
if !k1set {
return true
}
return k1 == k2
}
func minStr(k interface{} /*K*/, kset bool) string {
s := fmt.Sprintf("%v", k)
if !kset {
s = fmt.Sprintf("-∞ /* %s */", s)
}
return s
}
func maxStr(k interface{} /*K*/, kset bool) string {
s := fmt.Sprintf("%v", k)
if !kset {
s = fmt.Sprintf("+∞ /* %s */", s)
}
return s
}
// checkHit rescans t from root and checks that hit D, P, Kmin/Kmax and rest all match what they should
// it can be used after Set/Put/Delete to verify that all hit parameters were calculated correctly
func (t *Tree) checkHit(k interface{} /*K*/, op treeOp) {
......@@ -170,8 +196,10 @@ func (t *Tree) checkHit(k interface{} /*K*/, op treeOp) {
i, pi := -1, -1
var ok bool
var hitKmin, hitKmax xkey
var hitPKmin, hitPKmax xkey
var hitKmin, hitKmax interface {} /*K*/
var hitPKmin, hitPKmax interface {} /*K*/
var hitKminSet, hitKmaxSet bool
var hitPKminSet, hitPKmaxSet bool
loop:
// here the tree is immutable while we are rescanning it, which means
......@@ -188,6 +216,8 @@ loop:
case *x:
hitPKmin = hitKmin
hitPKmax = hitKmax
hitPKminSet = hitKminSet
hitPKmaxSet = hitKmaxSet
if ok {
i++
......@@ -198,18 +228,20 @@ loop:
q = p.x[pi].ch
if pi > 0 {
hitKmin.set(p.x[pi-1].k)
hitKmin = p.x[pi-1].k
hitKminSet = true
if hitPKmin.kset && t.cmp(hitKmin.k, hitPKmin.k) <= 0 {
bad("hitKmin not ↑: %v -> %v", hitPKmin.k, hitKmin.k)
if hitPKminSet && t.cmp(hitKmin, hitPKmin) <= 0 {
bad("hitKmin not ↑: %v -> %v", hitPKmin, hitKmin)
}
}
if pi < p.c { // pi = p.c means k = ∞
hitKmax.set(p.x[pi].k)
hitKmax = p.x[pi].k
hitKmaxSet = true
if hitPKmax.kset && t.cmp(hitKmax.k, hitPKmax.k) >= 0 {
bad("hitKmax not ↓: %v -> %v", hitPKmax.k, hitKmax.k)
if hitPKmaxSet && t.cmp(hitKmax, hitPKmax) >= 0 {
bad("hitKmax not ↓: %v -> %v", hitPKmax, hitKmax)
}
}
......@@ -242,19 +274,23 @@ loop:
}
}
if !(hitKmin == t.hitKmin && hitKmax == t.hitKmax) {
bad("hitK mismatch: [%v, %v) ; want [%v, %v)", t.hitKmin, t.hitKmax, hitKmin, hitKmax)
if !(xeq(t.hitKmin, hitKmin, t.hitKminSet, hitKminSet) && xeq(t.hitKmax, hitKmax, t.hitKmaxSet, hitKmaxSet)) {
bad("hitK mismatch: [%v, %v) ; want [%v, %v)",
minStr(t.hitKmin, t.hitKminSet), maxStr(t.hitKmax, t.hitKmaxSet),
minStr(hitKmin, hitKminSet), maxStr(hitKmax, hitKmaxSet))
}
if !(hitPKmin == t.hitPKmin && hitPKmax == t.hitPKmax) {
bad("hitPK mismatch: [%v, %v) ; want [%v, %v)", t.hitPKmin, t.hitPKmax, hitPKmin, hitPKmax)
if !(xeq(t.hitPKmin, hitPKmin, t.hitPKminSet, hitPKminSet) && xeq(t.hitPKmax, hitPKmax, t.hitPKmaxSet, hitPKmaxSet)) {
bad("hitPK mismatch: [%v, %v) ; want [%v, %v)",
minStr(t.hitPKmin, t.hitPKminSet), maxStr(t.hitPKmax, t.hitPKmaxSet),
minStr(hitPKmin, hitPKminSet), maxStr(hitPKmax, hitPKmaxSet))
}
if !(dd == t.hitD && i == t.hitDi) {
if !(t.hitD == dd && t.hitDi == i) {
bad("hitD mismatch: %v @%d ; want %v @%d", t.hitD, t.hitDi, dd, i)
}
if !(p == t.hitP && pi == t.hitPi) {
if !(t.hitP == p && t.hitPi == pi) {
bad("hitP mismatch: %v @%d ; want %v @%d", t.hitP, t.hitPi, p, pi)
}
......
......@@ -11,10 +11,10 @@ import (
)
const (
kx = 32 //TODO benchmark tune this number if using custom key/value type(s).
kd = 32 //TODO benchmark tune this number if using custom key/value type(s).
//kx = 2
//kd = 2
//kx = 32 //TODO benchmark tune this number if using custom key/value type(s).
//kd = 32 //TODO benchmark tune this number if using custom key/value type(s).
kx = 2
kd = 2
)
func init() {
......@@ -105,10 +105,16 @@ type (
hitDi int
hitP *x // parent & pos for data page (= nil/-1 if no parent)
hitPi int
hitKmin xkey // hitD allowed key range is [hitKmin, hitKmax)
hitKmax xkey
hitPKmin xkey // ----//--- for hitP
hitPKmax xkey
hitKmin interface{} /*K*/ // hitD allowed key range is [hitKmin, hitKmax)
hitKmax interface{} /*K*/
hitPKmin interface{} /*K*/ // ----//--- for hitP
hitPKmax interface{} /*K*/
hitKminSet bool // whether corresponding hitK* value is set
hitKmaxSet bool // if value is not set it is treated as ±∞ depending on context
hitPKminSet bool
hitPKmaxSet bool
}
xe struct { // x element
......@@ -120,11 +126,6 @@ type (
c int
x [2*kx + 2]xe
}
xkey struct { // key + whether value is present at all
k interface{} /*K*/
kset bool // if not set - k not present
}
)
var ( // R/O zero values
......@@ -151,10 +152,10 @@ func clr(q interface{}) {
}
}
func (xk *xkey) set(k interface{} /*K*/) {
xk.k = k
xk.kset = true
}
func (t *Tree) setHitKmin(k interface{} /*K*/) { t.hitKmin = k; t.hitKminSet = true }
func (t *Tree) setHitKmax(k interface{} /*K*/) { t.hitKmax = k; t.hitKmaxSet = true }
func (t *Tree) setHitPKmin(k interface{} /*K*/) { t.hitPKmin = k; t.hitPKminSet = true }
func (t *Tree) setHitPKmax(k interface{} /*K*/) { t.hitPKmax = k; t.hitPKmaxSet = true }
// -------------------------------------------------------------------------- x
......@@ -233,7 +234,8 @@ func (t *Tree) Clear() {
clr(t.r)
t.c, t.first, t.last, t.r = 0, nil, nil, nil
t.hitD, t.hitDi, t.hitP, t.hitPi = nil, -1, nil, -1
t.hitKmin, t.hitKmax, t.hitPKmin, t.hitPKmax = xkey{}, xkey{}, xkey{}, xkey{}
t.hitKmin, t.hitKmax, t.hitPKmin, t.hitPKmax = zk, zk, zk, zk
t.hitKminSet, t.hitKmaxSet, t.hitPKminSet, t.hitPKmaxSet = false, false, false, false
t.ver++
}
......@@ -309,7 +311,7 @@ func (t *Tree) catX(p, q, r *x, pi int) {
// true.
func (t *Tree) Delete(k interface{} /*K*/) (ok bool) {
//dbg("--- PRE Delete(%v)\t; %v @%d, [%v, %v) pk: [%v, %v)\n%s", k, t.hitD, t.hitDi, t.hitKmin, t.hitKmax, t.hitPKmin, t.hitPKmax, t.dump())
//defer t.checkHit(k, opDel)
defer t.checkHit(k, opDel)
//defer func() {
// dbg("--- POST\n%s\n====\n", t.dump())
//}()
......@@ -372,8 +374,8 @@ func (t *Tree) Delete(k interface{} /*K*/) (ok bool) {
return false
}
t.hitKmin, t.hitKmax = xkey{}, xkey{} // initially [-∞, +∞)
t.hitPKmin, t.hitPKmax = xkey{}, xkey{}
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for {
i, ok := t.find(q, k)
......@@ -390,17 +392,19 @@ func (t *Tree) Delete(k interface{} /*K*/) (ok bool) {
t.hitPKmin = t.hitKmin
t.hitPKmax = t.hitKmax
t.hitPKminSet = t.hitKminSet
t.hitPKmaxSet = t.hitKmaxSet
p = x
pi = i
q = x.x[pi].ch
if pi > 0 { // k=-∞ @-1
t.hitKmin.set(p.x[pi-1].k)
t.setHitKmin(p.x[pi-1].k)
}
if pi < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi].k)
t.setHitKmax(p.x[pi].k)
}
case *d:
......@@ -528,7 +532,7 @@ func (t *Tree) hitFind(k interface{} /*K*/) (i int, ok bool) {
switch cmp := t.cmp(k, hit.d[i].k); {
case cmp > 0:
if t.hitKmax.kset && t.cmp(k, t.hitKmax.k) >= 0 {
if t.hitKmaxSet && t.cmp(k, t.hitKmax) >= 0 {
// >= hitKmax
return -1, false
}
......@@ -537,7 +541,7 @@ func (t *Tree) hitFind(k interface{} /*K*/) (i int, ok bool) {
return t.find2(hit, k, i+1, hit.c-1)
case cmp < 0:
if t.hitKmin.kset && t.cmp(k, t.hitKmin.k) < 0 {
if t.hitKminSet && t.cmp(k, t.hitKmin) < 0 {
// < hitKmin
return -1, false
}
......@@ -626,7 +630,7 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{
l.mvL(q, 1)
t.insert(q, i-1, k, v)
p.x[pi-1].k = q.d[0].k
t.hitKmin.set(q.d[0].k)
t.setHitKmin(q.d[0].k)
//t.hitPi = pi already pre-set this way
return
}
......@@ -636,7 +640,7 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{
q.mvR(r, 1)
t.insert(q, i, k, v)
p.x[pi].k = r.d[0].k
t.hitKmax.set(r.d[0].k)
t.setHitKmax(r.d[0].k)
//t.hitPi = pi already pre-set this way
return
}
......@@ -644,10 +648,12 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{
t.insert(r, 0, k, v)
p.x[pi].k = k
t.hitKmin.set(k)
t.hitKmax = t.hitPKmax
t.setHitKmin(k)
if pi+1 < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi+1].k)
t.setHitKmax(p.x[pi+1].k)
} else {
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
t.hitPi = pi + 1
return
......@@ -712,7 +718,7 @@ func (t *Tree) SeekLast() (e *Enumerator, err error) {
// Set sets the value associated with k.
func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
//dbg("--- PRE Set(%v, %v)\t; %v @%d, [%v, %v) pk: [%v, %v)\n%s", k, v, t.hitD, t.hitDi, t.hitKmin, t.hitKmax, t.hitPKmin, t.hitPKmax, t.dump())
//defer t.checkHit(k, opSet)
defer t.checkHit(k, opSet)
//defer func() {
// dbg("--- POST\n%s\n====\n", t.dump())
//}()
......@@ -757,8 +763,8 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
return
}
t.hitKmin, t.hitKmax = xkey{}, xkey{} // initially [-∞, +∞)
t.hitPKmin, t.hitPKmax = xkey{}, xkey{}
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for {
i, ok := t.find(q, k)
......@@ -775,17 +781,19 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
t.hitPKmin = t.hitKmin
t.hitPKmax = t.hitKmax
t.hitPKminSet = t.hitKminSet
t.hitPKmaxSet = t.hitKmaxSet
p = x
pi = i
q = p.x[pi].ch
if pi > 0 { // k=-∞ @-1
t.hitKmin.set(p.x[pi-1].k)
t.setHitKmin(p.x[pi-1].k)
}
if pi < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi].k)
t.setHitKmax(p.x[pi].k)
}
case *d:
......@@ -824,7 +832,7 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
//
// modulo the differing return values.
func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists bool) (newV interface{} /*V*/, write bool)) (oldV interface{} /*V*/, written bool) {
//defer func () { t.checkHit(k, opPut(written)) }()
defer func () { t.checkHit(k, opPut(written)) }()
pi := -1
var p *x
q := t.r
......@@ -895,8 +903,8 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists
}
// data page not quickly found - search and descent from root
t.hitKmin, t.hitKmax = xkey{}, xkey{} // initially [-∞, +∞)
t.hitPKmin, t.hitPKmax = xkey{}, xkey{}
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for {
i, ok := t.find(q, k)
......@@ -913,17 +921,19 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists
t.hitPKmin = t.hitKmin
t.hitPKmax = t.hitKmax
t.hitPKminSet = t.hitKminSet
t.hitPKmaxSet = t.hitKmaxSet
p = x
pi = i
q = p.x[pi].ch
if pi > 0 { // k=-∞ @-1
t.hitKmin.set(p.x[pi-1].k)
t.setHitKmin(p.x[pi-1].k)
}
if pi < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi].k)
t.setHitKmax(p.x[pi].k)
}
case *d:
......@@ -998,15 +1008,17 @@ func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /
if i > kd {
t.insert(r, i-kd, k, v)
t.hitKmin.set(p.x[pi].k)
t.hitKmax = t.hitPKmax
t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi+1].k)
t.setHitKmax(p.x[pi+1].k)
} else {
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
t.hitPi = pi + 1
} else {
t.insert(q, i, k, v)
t.hitKmax.set(r.d[0].k)
t.setHitKmax(r.d[0].k)
//t.hitPi = pi already pre-set this way
}
}
......@@ -1032,13 +1044,15 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
if i > kx {
q = r
i -= kx + 1
t.hitKmin.set(p.x[pi].k)
t.hitKmax = t.hitPKmax
t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi+1].k)
t.setHitKmax(p.x[pi+1].k)
} else {
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
} else {
t.hitKmax.set(p.x[pi].k)
t.setHitKmax(p.x[pi].k)
}
return q, i
......@@ -1051,7 +1065,7 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
if l != nil && l.c+q.c >= 2*kd {
l.mvR(q, 1)
p.x[pi-1].k = q.d[0].k
t.hitKmin.set(q.d[0].k)
t.setHitKmin(q.d[0].k)
//t.hitPi = pi already pre-set this way
t.hitDi += 1
return
......@@ -1060,7 +1074,7 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
if r != nil && q.c+r.c >= 2*kd {
q.mvL(r, 1)
p.x[pi].k = r.d[0].k
t.hitKmax.set(r.d[0].k)
t.setHitKmax(r.d[0].k)
//t.hitPi = pi already pre-set this way
// hitDi stays the same
r.d[r.c] = zde // GC
......@@ -1073,13 +1087,14 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
pi--
t.cat(p, l, q, pi)
t.hitKmin = t.hitPKmin
t.hitKminSet = t.hitPKminSet // XXX move vvv under else ? (but vs t.r == l)
if t.r == l {
// cat removed p
t.hitP = nil
t.hitPi = -1
} else {
if pi > 0 { // k=-∞ @-1
t.hitKmin.set(p.x[pi-1].k)
t.setHitKmin(p.x[pi-1].k)
}
t.hitPi = pi
}
......@@ -1089,13 +1104,14 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
t.cat(p, q, r, pi)
// hitD/hitDi stays unchanged
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet // XXX move vvv under else ? (but vs t.r == q)
if t.r == q {
// cat removed p
t.hitP = nil
t.hitPi = -1
} else {
if pi < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi].k)
t.setHitKmax(p.x[pi].k)
}
//t.hitPi = pi already pre-set this way
}
......@@ -1123,7 +1139,7 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
i++
l.c--
p.x[pi-1].k = l.x[l.c].k
t.hitKmin.set(l.x[l.c].k)
t.setHitKmin(l.x[l.c].k)
return q, i
}
......@@ -1132,7 +1148,7 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
q.c++
q.x[q.c].ch = r.x[0].ch
p.x[pi].k = r.x[0].k
t.hitKmax.set(r.x[0].k)
t.setHitKmax(r.x[0].k)
copy(r.x[:], r.x[1:r.c])
r.c--
rc := r.c
......@@ -1147,17 +1163,21 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
pi--
t.catX(p, l, q, pi)
q = l
t.hitKmin = t.hitPKmin
if t.r != q && pi > 0 { // k=+∞ @p.c
t.hitKmin.set(p.x[pi-1].k)
t.setHitKmin(p.x[pi-1].k)
} else {
t.hitKmin = t.hitPKmin
t.hitKminSet = t.hitPKminSet
}
return q, i
}
t.catX(p, q, r, pi)
t.hitKmax = t.hitPKmax
if t.r != q && pi < p.c { // k=+∞ @p.c
t.hitKmax.set(p.x[pi].k)
t.setHitKmax(p.x[pi].k)
} else {
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
return q, i
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment