Commit fe0f712e authored by Kirill Smelkov's avatar Kirill Smelkov

X storage/fs1/fsb: regenerate @x/bulkload

parent 91340c7a
// DO NOT EDIT - AUTOGENERATED (by gen-fsbtree from github.com/cznic/b aaaa43c) // DO NOT EDIT - AUTOGENERATED (by gen-fsbtree from github.com/cznic/b 4efd872)
// KEY=zodb.Oid VALUE=int64 // KEY=zodb.Oid VALUE=int64
// ---- 8< ---- // ---- 8< ----
...@@ -19,6 +19,8 @@ import ( ...@@ -19,6 +19,8 @@ import (
const ( const (
kx = 32 //TODO benchmark tune this number if using custom key/value type(s). 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). kd = 32 //TODO benchmark tune this number if using custom key/value type(s).
//kx = 2
//kd = 2
) )
func init() { func init() {
...@@ -42,6 +44,8 @@ type btTpool struct{ sync.Pool } ...@@ -42,6 +44,8 @@ type btTpool struct{ sync.Pool }
func (p *btTpool) get() *Tree { func (p *btTpool) get() *Tree {
x := p.Get().(*Tree) x := p.Get().(*Tree)
x.hitDi = -1
x.hitPi = -1
return x return x
} }
...@@ -99,6 +103,22 @@ type ( ...@@ -99,6 +103,22 @@ type (
last *d last *d
r interface{} r interface{}
ver int64 ver int64
// information about last data page which Set/Put/Delete accessed
hitD *d // data page & pos of last write access
hitDi int
hitP *x // parent & pos for data page (= nil/-1 if no parent)
hitPi int
hitKmin zodb.Oid // hitD allowed key range is [hitKmin, hitKmax)
hitKmax zodb.Oid
hitPKmin zodb.Oid // ----//--- for hitP
hitPKmax zodb.Oid
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 xe struct { // x element
...@@ -136,6 +156,11 @@ func clr(q interface{}) { ...@@ -136,6 +156,11 @@ func clr(q interface{}) {
} }
} }
func (t *Tree) setHitKmin(k zodb.Oid) { t.hitKmin = k; t.hitKminSet = true }
func (t *Tree) setHitKmax(k zodb.Oid) { t.hitKmax = k; t.hitKmaxSet = true }
func (t *Tree) setHitPKmin(k zodb.Oid) { t.hitPKmin = k; t.hitPKminSet = true }
func (t *Tree) setHitPKmax(k zodb.Oid) { t.hitPKmax = k; t.hitPKmaxSet = true }
// -------------------------------------------------------------------------- x // -------------------------------------------------------------------------- x
func newX(ch0 interface{}) *x { func newX(ch0 interface{}) *x {
...@@ -212,6 +237,9 @@ func (t *Tree) Clear() { ...@@ -212,6 +237,9 @@ func (t *Tree) Clear() {
clr(t.r) clr(t.r)
t.c, t.first, t.last, t.r = 0, nil, nil, nil 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 = zk, zk, zk, zk
t.hitKminSet, t.hitKmaxSet, t.hitPKminSet, t.hitPKmaxSet = false, false, false, false
t.ver++ t.ver++
} }
...@@ -286,6 +314,63 @@ func (t *Tree) catX(p, q, r *x, pi int) { ...@@ -286,6 +314,63 @@ func (t *Tree) catX(p, q, r *x, pi int) {
// Delete removes the k's KV pair, if it exists, in which case Delete returns // Delete removes the k's KV pair, if it exists, in which case Delete returns
// true. // true.
func (t *Tree) Delete(k zodb.Oid) (ok bool) { func (t *Tree) Delete(k zodb.Oid) (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 func() {
// dbg("--- POST\n%s\n====\n", t.dump())
//}()
// check if we can do the delete nearby previous change
i, ok := t.hitFind(k)
if i >= 0 {
dd := t.hitD
switch {
case !ok:
// tried to delete last or element past max k in hitD
// see also "extract rule" below
if i >= dd.c {
i--
}
t.hitDi = i
return false
case dd.c > kd:
t.extract(dd, i)
// extract rule for t.hitDi
if t.hitDi >= dd.c {
t.hitDi--
}
return true
// here: need to extract / underflow but we have to check: if underflowing
// would cause upper level underflow (underflowX) -> we cannot extract /
// underflow here - need to do the usual scan from root to underflow index pages.
default:
p, pi := t.hitP, t.hitPi
if p != nil && p.c < kx && p != t.r {
break
}
t.extract(dd, i)
if p != nil {
// NOTE underflow corrects hit D,Di, P,Pi, Kmin, Kmax as needed
t.underflow(p, dd, pi)
} else if t.c == 0 {
t.Clear()
}
// extract rule for t.hitDi
if t.hitD != nil && t.hitDi >= t.hitD.c {
t.hitDi--
}
return true
}
}
// data page not quickly found - search and descent from root
pi := -1 pi := -1
var p *x var p *x
q := t.r q := t.r
...@@ -293,45 +378,72 @@ func (t *Tree) Delete(k zodb.Oid) (ok bool) { ...@@ -293,45 +378,72 @@ func (t *Tree) Delete(k zodb.Oid) (ok bool) {
return false return false
} }
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for { for {
var i int switch x := q.(type) {
i, ok = t.find(q, k) case *x:
if ok { i, ok := t.findX(x, k)
switch x := q.(type) { if ok {
case *x: i++
if x.c < kx && q != t.r { }
x, i = t.underflowX(p, x, pi, i)
} if x.c < kx && q != t.r {
pi = i + 1 // NOTE underflowX corrects hit Kmin and Kmax as needed
p = x x, i = t.underflowX(p, x, pi, i)
q = x.x[pi].ch }
ok = false
continue t.hitPKmin = t.hitKmin
case *d: t.hitPKmax = t.hitKmax
t.extract(x, i) t.hitPKminSet = t.hitKminSet
if x.c >= kd { t.hitPKmaxSet = t.hitKmaxSet
return true
p = x
pi = i
q = x.x[pi].ch
if pi > 0 { // k=-∞ @-1
t.setHitKmin(p.x[pi-1].k)
}
if pi < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi].k)
}
case *d:
i, ok := t.find(x, k)
// data page found - perform the delete
t.hitP = p
t.hitPi = pi
if !ok {
t.hitD = x
if i >= x.c {
// tried to delete last or element past max k in hitD
i--
} }
t.hitDi = i
return false
}
t.extract(x, i)
if x.c < kd {
if q != t.r { if q != t.r {
// NOTE underflow corrects hit D,Di, P,Pi, Kmin, Kmax as needed
t.underflow(p, x, pi) t.underflow(p, x, pi)
} else if t.c == 0 { } else if t.c == 0 {
t.Clear() t.Clear()
} }
return true
} }
}
switch x := q.(type) { // extract rule for t.hitDi
case *x: if t.hitD != nil && t.hitDi >= t.hitD.c {
if x.c < kx && q != t.r { t.hitDi--
x, i = t.underflowX(p, x, pi, i)
} }
pi = i return true
p = x
q = x.x[i].ch
case *d:
return false
} }
} }
} }
...@@ -345,45 +457,104 @@ func (t *Tree) extract(q *d, i int) { // (r int64) { ...@@ -345,45 +457,104 @@ func (t *Tree) extract(q *d, i int) { // (r int64) {
} }
q.d[q.c] = zde // GC q.d[q.c] = zde // GC
t.c-- t.c--
t.hitD = q
// NOTE extract users - in the end - must decrement t.hitDi if t.hitDi == t.hitD.c
// we are not doing it right here because unaltered position is
// required in case merging a right sibling data page will be needed.
t.hitDi = i
return return
} }
func (t *Tree) find(q interface{}, k zodb.Oid) (i int, ok bool) { func (t *Tree) findX(x *x, k zodb.Oid) (i int, ok bool) {
var mk zodb.Oid
l := 0 l := 0
switch x := q.(type) { h := x.c - 1
case *x: for l <= h {
h := x.c - 1 m := (l + h) >> 1
for l <= h { switch cmp := oidCmp(k, x.x[m].k); {
m := (l + h) >> 1 case cmp > 0:
mk = x.x[m].k l = m + 1
switch cmp := oidCmp(k, mk); { case cmp == 0:
case cmp > 0: return m, true
l = m + 1 default:
case cmp == 0: h = m - 1
return m, true
default:
h = m - 1
}
} }
case *d: }
h := x.c - 1 return l, false
for l <= h { }
m := (l + h) >> 1
mk = x.d[m].k func (t *Tree) find(x *d, k zodb.Oid) (i int, ok bool) {
switch cmp := oidCmp(k, mk); { l := 0
case cmp > 0: h := x.c - 1
l = m + 1 for l <= h {
case cmp == 0: m := (l + h) >> 1
return m, true switch cmp := oidCmp(k, x.d[m].k); {
default: case cmp > 0:
h = m - 1 l = m + 1
} case cmp == 0:
return m, true
default:
h = m - 1
} }
} }
return l, false return l, false
} }
// hitFind returns position for k in previously hit data page
// if k should not reside in hit range: -1, false is returned
// otherwise returns are:
// - i: index corresponding to data entry in t.hitD with min(k' : k <= k')
// - ok: whether k' == k
func (t *Tree) hitFind(k zodb.Oid) (i int, ok bool) {
// DEBUG: enable this to test how slow path computes hit{Kmin,Kmax} on all keys
//return -1, false
hit := t.hitD
if hit == nil {
return -1, false
}
i = t.hitDi
var h int
switch cmp := oidCmp(k, hit.d[i].k); {
case cmp > 0:
if t.hitKmaxSet && oidCmp(k, t.hitKmax) >= 0 {
// >= hitKmax
return -1, false
}
// NOTE we are ok if i+1=hit.c -> hit.c will be returned
i, h = i+1, hit.c-1
case cmp < 0:
if t.hitKminSet && oidCmp(k, t.hitKmin) < 0 {
// < hitKmin
return -1, false
}
// NOTE we are ok if i-1=-1 -> 0 will be returned
i, h = 0, i-1
default:
return i, true
}
for i <= h {
m := (i + h) >> 1
switch cmp := oidCmp(k, hit.d[m].k); {
case cmp > 0:
i = m + 1
case cmp == 0:
return m, true
default:
h = m - 1
}
}
return i, false
}
// First returns the first item of the tree in the key collating order, or // First returns the first item of the tree in the key collating order, or
// (zero-value, zero-value) if the tree is empty. // (zero-value, zero-value) if the tree is empty.
func (t *Tree) First() (k zodb.Oid, v int64) { func (t *Tree) First() (k zodb.Oid, v int64) {
...@@ -403,21 +574,20 @@ func (t *Tree) Get(k zodb.Oid) (v int64, ok bool) { ...@@ -403,21 +574,20 @@ func (t *Tree) Get(k zodb.Oid) (v int64, ok bool) {
} }
for { for {
var i int
if i, ok = t.find(q, k); ok {
switch x := q.(type) {
case *x:
q = x.x[i+1].ch
continue
case *d:
return x.d[i].v, true
}
}
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
q = x.x[i].ch q = x.x[i].ch
default:
return case *d:
i, ok := t.find(x, k)
if ok {
return x.d[i].v, true
}
return v, ok
} }
} }
} }
...@@ -432,6 +602,8 @@ func (t *Tree) insert(q *d, i int, k zodb.Oid, v int64) *d { ...@@ -432,6 +602,8 @@ func (t *Tree) insert(q *d, i int, k zodb.Oid, v int64) *d {
q.c = c q.c = c
q.d[i].k, q.d[i].v = k, v q.d[i].k, q.d[i].v = k, v
t.c++ t.c++
t.hitD = q
t.hitDi = i
return q return q
} }
...@@ -458,6 +630,8 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k zodb.Oid, v int64) { ...@@ -458,6 +630,8 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k zodb.Oid, v int64) {
l.mvL(q, 1) l.mvL(q, 1)
t.insert(q, i-1, k, v) t.insert(q, i-1, k, v)
p.x[pi-1].k = q.d[0].k p.x[pi-1].k = q.d[0].k
t.setHitKmin(q.d[0].k)
//t.hitPi = pi already pre-set this way
return return
} }
...@@ -466,11 +640,22 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k zodb.Oid, v int64) { ...@@ -466,11 +640,22 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k zodb.Oid, v int64) {
q.mvR(r, 1) q.mvR(r, 1)
t.insert(q, i, k, v) t.insert(q, i, k, v)
p.x[pi].k = r.d[0].k p.x[pi].k = r.d[0].k
t.setHitKmax(r.d[0].k)
//t.hitPi = pi already pre-set this way
return return
} }
t.insert(r, 0, k, v) t.insert(r, 0, k, v)
p.x[pi].k = k p.x[pi].k = k
t.setHitKmin(k)
if pi+1 < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi+1].k)
} else {
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
t.hitPi = pi + 1
return return
} }
...@@ -488,22 +673,17 @@ func (t *Tree) Seek(k zodb.Oid) (e *Enumerator, ok bool) { ...@@ -488,22 +673,17 @@ func (t *Tree) Seek(k zodb.Oid) (e *Enumerator, ok bool) {
} }
for { for {
var i int
if i, ok = t.find(q, k); ok {
switch x := q.(type) {
case *x:
q = x.x[i+1].ch
continue
case *d:
return btEPool.get(nil, ok, i, k, x, t, t.ver), true
}
}
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
q = x.x[i].ch q = x.x[i].ch
case *d: case *d:
return btEPool.get(nil, ok, i, k, x, t, t.ver), false i, ok := t.find(x, k)
return btEPool.get(nil, ok, i, k, x, t, t.ver), ok
} }
} }
} }
...@@ -532,11 +712,43 @@ func (t *Tree) SeekLast() (e *Enumerator, err error) { ...@@ -532,11 +712,43 @@ func (t *Tree) SeekLast() (e *Enumerator, err error) {
// Set sets the value associated with k. // Set sets the value associated with k.
func (t *Tree) Set(k zodb.Oid, v int64) { func (t *Tree) Set(k zodb.Oid, v int64) {
//dbg("--- PRE Set(%v, %v)\n%s", k, v, t.dump()) //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 func() { //defer func() {
// dbg("--- POST\n%s\n====\n", t.dump()) // dbg("--- POST\n%s\n====\n", t.dump())
//}() //}()
// check if we can do the update nearby previous change
i, ok := t.hitFind(k)
if i >= 0 {
dd := t.hitD
switch {
case ok:
dd.d[i].v = v
t.hitDi = i
return
case dd.c < 2*kd:
t.insert(dd, i, k, v)
return
// here: need to overflow but we have to check: if overflowing would
// cause upper level overflow (splitX) -> we cannot overflow here -
// - need to do the usual scan from root to split index pages.
default:
p, pi := t.hitP, t.hitPi
if p != nil && p.c > 2*kx {
break
}
// NOTE overflow corrects hit Kmin, Kmax and Pi as needed
t.overflow(p, dd, pi, i, k, v)
return
}
}
// data page not quickly found - search and descent from root
pi := -1 pi := -1
var p *x var p *x
q := t.r q := t.r
...@@ -546,39 +758,59 @@ func (t *Tree) Set(k zodb.Oid, v int64) { ...@@ -546,39 +758,59 @@ func (t *Tree) Set(k zodb.Oid, v int64) {
return return
} }
for { t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
i, ok := t.find(q, k) t.hitPKminSet, t.hitPKmaxSet = false, false
if ok {
switch x := q.(type) {
case *x:
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
p = x
q = x.x[i+1].ch
continue
case *d:
x.d[i].v = v
}
return
}
for {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
if x.c > 2*kx { if x.c > 2*kx {
// NOTE splitX corrects hit Kmin and Kmax as needed
x, i = t.splitX(p, x, pi, i) x, i = t.splitX(p, x, pi, i)
} }
pi = i
t.hitPKmin = t.hitKmin
t.hitPKmax = t.hitKmax
t.hitPKminSet = t.hitKminSet
t.hitPKmaxSet = t.hitKmaxSet
p = x p = x
q = x.x[i].ch pi = i
q = p.x[pi].ch
if pi > 0 { // k=-∞ @-1
t.setHitKmin(p.x[pi-1].k)
}
if pi < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi].k)
}
case *d: case *d:
i, ok := t.find(x, k)
// data page found - perform the update
t.hitP = p
t.hitPi = pi
switch { switch {
case ok:
x.d[i].v = v
t.hitD, t.hitDi = x, i
case x.c < 2*kd: case x.c < 2*kd:
t.insert(x, i, k, v) t.insert(x, i, k, v)
default: default:
// NOTE overflow corrects hit Kmin, Kmax and Pi as needed
t.overflow(p, x, pi, i, k, v) t.overflow(p, x, pi, i, k, v)
} }
return return
} }
} }
...@@ -597,6 +829,7 @@ func (t *Tree) Set(k zodb.Oid, v int64) { ...@@ -597,6 +829,7 @@ func (t *Tree) Set(k zodb.Oid, v int64) {
// //
// modulo the differing return values. // modulo the differing return values.
func (t *Tree) Put(k zodb.Oid, upd func(oldV int64, exists bool) (newV int64, write bool)) (oldV int64, written bool) { func (t *Tree) Put(k zodb.Oid, upd func(oldV int64, exists bool) (newV int64, write bool)) (oldV int64, written bool) {
//defer func () { t.checkHit(k, opPut(written)) }()
pi := -1 pi := -1
var p *x var p *x
q := t.r q := t.r
...@@ -613,50 +846,131 @@ func (t *Tree) Put(k zodb.Oid, upd func(oldV int64, exists bool) (newV int64, wr ...@@ -613,50 +846,131 @@ func (t *Tree) Put(k zodb.Oid, upd func(oldV int64, exists bool) (newV int64, wr
return return
} }
for { // check if we can do the update nearby previous change
i, ok := t.find(q, k) i, ok := t.hitFind(k)
if ok { if i >= 0 {
switch x := q.(type) { dd := t.hitD
case *x:
if x.c > 2*kx { switch {
x, i = t.splitX(p, x, pi, i) case ok:
} oldV = dd.d[i].v
pi = i + 1 newV, written = upd(oldV, true)
p = x if written {
q = x.x[i+1].ch dd.d[i].v = newV
continue }
case *d: t.hitDi = i
oldV = x.d[i].v return
newV, written = upd(oldV, true)
if !written { case dd.c < 2*kd:
return newV, written = upd(newV, false)
if written {
t.insert(dd, i, k, newV)
} else {
t.hitDi = i
// if it was only Get landed past max key - adjust it to valid entry
if t.hitDi >= dd.c {
t.hitDi--
} }
}
return
// here: need to overflow but we have to check: if overflowing would
// cause upper level overflow (splitX) -> we cannot overflow here -
// - need to do the usual scan from root to split index pages.
default:
p, pi := t.hitP, t.hitPi
if p != nil && p.c > 2*kx {
break
}
newV, written = upd(newV, false)
x.d[i].v = newV if written {
// NOTE overflow corrects hit Kmin, Kmax and Pi as needed
t.overflow(p, dd, pi, i, k, newV)
} else {
t.hitDi = i
// see about "valid entry" ^^^
if t.hitDi >= dd.c {
t.hitDi--
}
} }
return return
} }
}
// data page not quickly found - search and descent from root
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
if x.c > 2*kx { if x.c > 2*kx {
// NOTE splitX corrects hit Kmin and Kmax as needed
x, i = t.splitX(p, x, pi, i) x, i = t.splitX(p, x, pi, i)
} }
pi = i
t.hitPKmin = t.hitKmin
t.hitPKmax = t.hitKmax
t.hitPKminSet = t.hitKminSet
t.hitPKmaxSet = t.hitKmaxSet
p = x p = x
q = x.x[i].ch pi = i
case *d: // new KV pair q = p.x[pi].ch
newV, written = upd(newV, false)
if !written { if pi > 0 { // k=-∞ @-1
return t.setHitKmin(p.x[pi-1].k)
}
if pi < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi].k)
} }
case *d:
i, ok := t.find(x, k)
// data page found - perform the update
t.hitP = p
t.hitPi = pi
switch { switch {
case x.c < 2*kd: case ok:
t.insert(x, i, k, newV) oldV = x.d[i].v
newV, written = upd(oldV, true)
if written {
x.d[i].v = newV
}
t.hitD, t.hitDi = x, i
default: default:
t.overflow(p, x, pi, i, k, newV) newV, written = upd(newV, false)
if !written {
t.hitD, t.hitDi = x, i
// see about "valid entry" ^^^
if t.hitDi >= x.c {
t.hitDi--
}
break
}
switch {
case x.c < 2*kd:
t.insert(x, i, k, newV)
default:
// NOTE overflow corrects hit Kmin, Kmax and Pi as needed
t.overflow(p, x, pi, i, k, newV)
}
} }
return return
} }
} }
...@@ -680,21 +994,32 @@ func (t *Tree) split(p *x, q *d, pi, i int, k zodb.Oid, v int64) { ...@@ -680,21 +994,32 @@ func (t *Tree) split(p *x, q *d, pi, i int, k zodb.Oid, v int64) {
} }
q.c = kd q.c = kd
r.c = kd r.c = kd
var done bool
if i > kd {
done = true
t.insert(r, i-kd, k, v)
}
if pi >= 0 { if pi >= 0 {
p.insert(pi, r.d[0].k, r) p.insert(pi, r.d[0].k, r)
} else { } else {
t.r = newX(q).insert(0, r.d[0].k, r) p = newX(q).insert(0, r.d[0].k, r)
} pi = 0
if done { t.r = p
return t.hitP = p
t.hitPi = pi
} }
t.insert(q, i, k, v) if i > kd {
t.insert(r, i-kd, k, v)
t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c
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.setHitKmax(r.d[0].k)
//t.hitPi = pi already pre-set this way
}
} }
func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) { func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
...@@ -705,36 +1030,31 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) { ...@@ -705,36 +1030,31 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
r.c = kx r.c = kx
if pi >= 0 { if pi >= 0 {
p.insert(pi, q.x[kx].k, r) p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk } else {
for i := range q.x[kx+1:] { p = newX(q).insert(0, q.x[kx].k, r)
q.x[kx+i+1] = zxe pi = 0
} t.r = p
switch {
case i < kx:
return q, i
case i == kx:
return p, pi
default: // i > kx
return r, i - kx - 1
}
} }
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk q.x[kx].k = zk
for i := range q.x[kx+1:] { for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe q.x[kx+i+1] = zxe
} }
if i > kx {
switch { q = r
case i < kx: i -= kx + 1
return q, i t.setHitKmin(p.x[pi].k)
case i == kx: if pi+1 < p.c { // k=+∞ @p.c
return nr, 0 t.setHitKmax(p.x[pi+1].k)
default: // i > kx } else {
return r, i - kx - 1 t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
} else {
t.setHitKmax(p.x[pi].k)
} }
return q, i
} }
func (t *Tree) underflow(p *x, q *d, pi int) { func (t *Tree) underflow(p *x, q *d, pi int) {
...@@ -744,22 +1064,56 @@ func (t *Tree) underflow(p *x, q *d, pi int) { ...@@ -744,22 +1064,56 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
if l != nil && l.c+q.c >= 2*kd { if l != nil && l.c+q.c >= 2*kd {
l.mvR(q, 1) l.mvR(q, 1)
p.x[pi-1].k = q.d[0].k p.x[pi-1].k = q.d[0].k
t.setHitKmin(q.d[0].k)
//t.hitPi = pi already pre-set this way
t.hitDi += 1
return return
} }
if r != nil && q.c+r.c >= 2*kd { if r != nil && q.c+r.c >= 2*kd {
q.mvL(r, 1) q.mvL(r, 1)
p.x[pi].k = r.d[0].k p.x[pi].k = 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 r.d[r.c] = zde // GC
return return
} }
if l != nil { if l != nil {
t.cat(p, l, q, pi-1) t.hitD = l
t.hitDi += l.c
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.setHitKmin(p.x[pi-1].k)
}
t.hitPi = pi
}
return return
} }
t.cat(p, q, r, pi) 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.setHitKmax(p.x[pi].k)
}
//t.hitPi = pi already pre-set this way
}
} }
func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
...@@ -784,6 +1138,7 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { ...@@ -784,6 +1138,7 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
i++ i++
l.c-- l.c--
p.x[pi-1].k = l.x[l.c].k p.x[pi-1].k = l.x[l.c].k
t.setHitKmin(l.x[l.c].k)
return q, i return q, i
} }
...@@ -792,6 +1147,7 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { ...@@ -792,6 +1147,7 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
q.c++ q.c++
q.x[q.c].ch = r.x[0].ch q.x[q.c].ch = r.x[0].ch
p.x[pi].k = r.x[0].k p.x[pi].k = r.x[0].k
t.setHitKmax(r.x[0].k)
copy(r.x[:], r.x[1:r.c]) copy(r.x[:], r.x[1:r.c])
r.c-- r.c--
rc := r.c rc := r.c
...@@ -803,12 +1159,25 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { ...@@ -803,12 +1159,25 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
if l != nil { if l != nil {
i += l.c + 1 i += l.c + 1
t.catX(p, l, q, pi-1) pi--
t.catX(p, l, q, pi)
q = l q = l
if t.r != q && pi > 0 { // k=+∞ @p.c
t.setHitKmin(p.x[pi-1].k)
} else {
t.hitKmin = t.hitPKmin
t.hitKminSet = t.hitPKminSet
}
return q, i return q, i
} }
t.catX(p, q, r, pi) t.catX(p, q, r, pi)
if t.r != q && pi < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi].k)
} else {
t.hitKmax = t.hitPKmax
t.hitKmaxSet = t.hitPKmaxSet
}
return q, i return q, i
} }
......
// DO NOT EDIT - AUTOGENERATED (by gen-fsbtree from github.com/cznic/b aaaa43c) // DO NOT EDIT - AUTOGENERATED (by gen-fsbtree from github.com/cznic/b 4efd872)
// ---- 8< ---- // ---- 8< ----
package fsb package fsb
import ( import (
......
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