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
// ---- 8< ----
......@@ -19,6 +19,8 @@ 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
)
func init() {
......@@ -42,6 +44,8 @@ type btTpool struct{ sync.Pool }
func (p *btTpool) get() *Tree {
x := p.Get().(*Tree)
x.hitDi = -1
x.hitPi = -1
return x
}
......@@ -99,6 +103,22 @@ type (
last *d
r interface{}
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
......@@ -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
func newX(ch0 interface{}) *x {
......@@ -212,6 +237,9 @@ 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 = zk, zk, zk, zk
t.hitKminSet, t.hitKmaxSet, t.hitPKminSet, t.hitPKmaxSet = false, false, false, false
t.ver++
}
......@@ -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
// true.
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
var p *x
q := t.r
......@@ -293,45 +378,72 @@ func (t *Tree) Delete(k zodb.Oid) (ok bool) {
return false
}
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for {
var i int
i, ok = t.find(q, k)
if ok {
switch x := q.(type) {
case *x:
if x.c < kx && q != t.r {
x, i = t.underflowX(p, x, pi, i)
}
pi = i + 1
p = x
q = x.x[pi].ch
ok = false
continue
case *d:
t.extract(x, i)
if x.c >= kd {
return true
switch x := q.(type) {
case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
if x.c < kx && q != t.r {
// NOTE underflowX corrects hit Kmin and Kmax as needed
x, i = t.underflowX(p, x, pi, i)
}
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.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 {
// NOTE underflow corrects hit D,Di, P,Pi, Kmin, Kmax as needed
t.underflow(p, x, pi)
} else if t.c == 0 {
t.Clear()
}
return true
}
}
switch x := q.(type) {
case *x:
if x.c < kx && q != t.r {
x, i = t.underflowX(p, x, pi, i)
// extract rule for t.hitDi
if t.hitD != nil && t.hitDi >= t.hitD.c {
t.hitDi--
}
pi = i
p = x
q = x.x[i].ch
case *d:
return false
return true
}
}
}
......@@ -345,45 +457,104 @@ func (t *Tree) extract(q *d, i int) { // (r int64) {
}
q.d[q.c] = zde // GC
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
}
func (t *Tree) find(q interface{}, k zodb.Oid) (i int, ok bool) {
var mk zodb.Oid
func (t *Tree) findX(x *x, k zodb.Oid) (i int, ok bool) {
l := 0
switch x := q.(type) {
case *x:
h := x.c - 1
for l <= h {
m := (l + h) >> 1
mk = x.x[m].k
switch cmp := oidCmp(k, mk); {
case cmp > 0:
l = m + 1
case cmp == 0:
return m, true
default:
h = m - 1
}
h := x.c - 1
for l <= h {
m := (l + h) >> 1
switch cmp := oidCmp(k, x.x[m].k); {
case cmp > 0:
l = m + 1
case cmp == 0:
return m, true
default:
h = m - 1
}
case *d:
h := x.c - 1
for l <= h {
m := (l + h) >> 1
mk = x.d[m].k
switch cmp := oidCmp(k, mk); {
case cmp > 0:
l = m + 1
case cmp == 0:
return m, true
default:
h = m - 1
}
}
return l, false
}
func (t *Tree) find(x *d, k zodb.Oid) (i int, ok bool) {
l := 0
h := x.c - 1
for l <= h {
m := (l + h) >> 1
switch cmp := oidCmp(k, x.d[m].k); {
case cmp > 0:
l = m + 1
case cmp == 0:
return m, true
default:
h = m - 1
}
}
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
// (zero-value, zero-value) if the tree is empty.
func (t *Tree) First() (k zodb.Oid, v int64) {
......@@ -403,21 +574,20 @@ func (t *Tree) Get(k zodb.Oid) (v int64, ok bool) {
}
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) {
case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
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 {
q.c = c
q.d[i].k, q.d[i].v = k, v
t.c++
t.hitD = q
t.hitDi = i
return q
}
......@@ -458,6 +630,8 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k zodb.Oid, v int64) {
l.mvL(q, 1)
t.insert(q, i-1, k, v)
p.x[pi-1].k = q.d[0].k
t.setHitKmin(q.d[0].k)
//t.hitPi = pi already pre-set this way
return
}
......@@ -466,11 +640,22 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k zodb.Oid, v int64) {
q.mvR(r, 1)
t.insert(q, i, k, v)
p.x[pi].k = r.d[0].k
t.setHitKmax(r.d[0].k)
//t.hitPi = pi already pre-set this way
return
}
t.insert(r, 0, k, v)
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
}
......@@ -488,22 +673,17 @@ func (t *Tree) Seek(k zodb.Oid) (e *Enumerator, ok bool) {
}
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) {
case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
q = x.x[i].ch
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) {
// Set sets the value associated with k.
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() {
// 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
var p *x
q := t.r
......@@ -546,39 +758,59 @@ func (t *Tree) Set(k zodb.Oid, v int64) {
return
}
for {
i, ok := t.find(q, k)
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
}
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
for {
switch x := q.(type) {
case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
if x.c > 2*kx {
// NOTE splitX corrects hit Kmin and Kmax as needed
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
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:
i, ok := t.find(x, k)
// data page found - perform the update
t.hitP = p
t.hitPi = pi
switch {
case ok:
x.d[i].v = v
t.hitD, t.hitDi = x, i
case x.c < 2*kd:
t.insert(x, i, k, v)
default:
// NOTE overflow corrects hit Kmin, Kmax and Pi as needed
t.overflow(p, x, pi, i, k, v)
}
return
}
}
......@@ -597,6 +829,7 @@ func (t *Tree) Set(k zodb.Oid, v int64) {
//
// 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) {
//defer func () { t.checkHit(k, opPut(written)) }()
pi := -1
var p *x
q := t.r
......@@ -613,50 +846,131 @@ func (t *Tree) Put(k zodb.Oid, upd func(oldV int64, exists bool) (newV int64, wr
return
}
for {
i, ok := t.find(q, k)
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:
oldV = x.d[i].v
newV, written = upd(oldV, true)
if !written {
return
// check if we can do the update nearby previous change
i, ok := t.hitFind(k)
if i >= 0 {
dd := t.hitD
switch {
case ok:
oldV = dd.d[i].v
newV, written = upd(oldV, true)
if written {
dd.d[i].v = newV
}
t.hitDi = i
return
case dd.c < 2*kd:
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
}
}
// 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) {
case *x:
i, ok := t.findX(x, k)
if ok {
i++
}
if x.c > 2*kx {
// NOTE splitX corrects hit Kmin and Kmax as needed
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
q = x.x[i].ch
case *d: // new KV pair
newV, written = upd(newV, false)
if !written {
return
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:
i, ok := t.find(x, k)
// data page found - perform the update
t.hitP = p
t.hitPi = pi
switch {
case x.c < 2*kd:
t.insert(x, i, k, newV)
case ok:
oldV = x.d[i].v
newV, written = upd(oldV, true)
if written {
x.d[i].v = newV
}
t.hitD, t.hitDi = x, i
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
}
}
......@@ -680,21 +994,32 @@ func (t *Tree) split(p *x, q *d, pi, i int, k zodb.Oid, v int64) {
}
q.c = kd
r.c = kd
var done bool
if i > kd {
done = true
t.insert(r, i-kd, k, v)
}
if pi >= 0 {
p.insert(pi, r.d[0].k, r)
} else {
t.r = newX(q).insert(0, r.d[0].k, r)
}
if done {
return
p = newX(q).insert(0, r.d[0].k, r)
pi = 0
t.r = p
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) {
......@@ -705,36 +1030,31 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
r.c = kx
if pi >= 0 {
p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return p, pi
default: // i > kx
return r, i - kx - 1
}
} else {
p = newX(q).insert(0, q.x[kx].k, r)
pi = 0
t.r = p
}
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return nr, 0
default: // i > kx
return r, i - kx - 1
if i > kx {
q = r
i -= kx + 1
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
}
} else {
t.setHitKmax(p.x[pi].k)
}
return q, i
}
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 {
l.mvR(q, 1)
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
}
if r != nil && q.c+r.c >= 2*kd {
q.mvL(r, 1)
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
return
}
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
}
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) {
......@@ -784,6 +1138,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.setHitKmin(l.x[l.c].k)
return q, i
}
......@@ -792,6 +1147,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.setHitKmax(r.x[0].k)
copy(r.x[:], r.x[1:r.c])
r.c--
rc := r.c
......@@ -803,12 +1159,25 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
if l != nil {
i += l.c + 1
t.catX(p, l, q, pi-1)
pi--
t.catX(p, l, q, pi)
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
}
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
}
......
// 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< ----
package fsb
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