Switch from Godep to go vendoring
This commit is contained in:
parent
6b37713bc0
commit
cd317761c5
1504 changed files with 263076 additions and 34441 deletions
11
vendor/github.com/cznic/b/AUTHORS
generated
vendored
Normal file
11
vendor/github.com/cznic/b/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# This file lists authors for copyright purposes. This file is distinct from
|
||||
# the CONTRIBUTORS files. See the latter for an explanation.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
#
|
||||
# The email address is not required for organizations.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Jan Mercl <0xjnml@gmail.com>
|
12
vendor/github.com/cznic/b/CONTRIBUTORS
generated
vendored
Normal file
12
vendor/github.com/cznic/b/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# This file lists people who contributed code to this repository. The AUTHORS
|
||||
# file lists the copyright holders; this file lists people.
|
||||
#
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Brian Fallik <bfallik@gmail.com>
|
||||
Dan Kortschak <dan.kortschak@adelaide.edu.au>
|
||||
Jan Mercl <0xjnml@gmail.com>
|
||||
Nikifor Seryakov <nikandfor@gmail.com>
|
27
vendor/github.com/cznic/b/LICENSE
generated
vendored
Normal file
27
vendor/github.com/cznic/b/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2014 The b Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the names of the authors nor the names of the
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
53
vendor/github.com/cznic/b/Makefile
generated
vendored
Normal file
53
vendor/github.com/cznic/b/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Copyright 2014 The b Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
.PHONY: all todo clean cover generic mem nuke cpu
|
||||
|
||||
testbin=b.test
|
||||
|
||||
all: editor
|
||||
go build
|
||||
go vet
|
||||
golint .
|
||||
go install
|
||||
make todo
|
||||
|
||||
editor:
|
||||
gofmt -l -s -w .
|
||||
go test -i
|
||||
go test
|
||||
|
||||
clean:
|
||||
@go clean
|
||||
rm -f *~ *.out $(testbin)
|
||||
|
||||
cover:
|
||||
t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t
|
||||
|
||||
cpu:
|
||||
go test -c
|
||||
./$(testbin) -test.cpuprofile cpu.out
|
||||
go tool pprof --lines $(testbin) cpu.out
|
||||
|
||||
generic:
|
||||
@# writes to stdout a version where the type of key is KEY and the type
|
||||
@# of value is VALUE.
|
||||
@#
|
||||
@# Intended use is to replace all textual occurrences of KEY or VALUE in
|
||||
@# the output with your desired types.
|
||||
@sed -e 's|interface{}[^{]*/\*K\*/|KEY|g' -e 's|interface{}[^{]*/\*V\*/|VALUE|g' btree.go
|
||||
|
||||
mem:
|
||||
go test -c
|
||||
./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1
|
||||
go tool pprof --lines --web --alloc_space $(testbin) mem.out
|
||||
|
||||
nuke: clean
|
||||
rm -f *.test *.out
|
||||
|
||||
todo:
|
||||
@grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true
|
||||
@grep -n TODO *.go || true
|
||||
@grep -n BUG *.go || true
|
||||
@grep -n println *.go || true
|
10
vendor/github.com/cznic/b/README.md
generated
vendored
Normal file
10
vendor/github.com/cznic/b/README.md
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
b
|
||||
=
|
||||
|
||||
Package b implements a B+tree.
|
||||
|
||||
Installation:
|
||||
|
||||
$ go get github.com/cznic/b
|
||||
|
||||
Documentation: [godoc.org/github.com/cznic/b](http://godoc.org/github.com/cznic/b)
|
1349
vendor/github.com/cznic/b/all_test.go
generated
vendored
Normal file
1349
vendor/github.com/cznic/b/all_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
929
vendor/github.com/cznic/b/btree.go
generated
vendored
Normal file
929
vendor/github.com/cznic/b/btree.go
generated
vendored
Normal file
|
@ -0,0 +1,929 @@
|
|||
// Copyright 2014 The b Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package b
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
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).
|
||||
)
|
||||
|
||||
func init() {
|
||||
if kd < 1 {
|
||||
panic(fmt.Errorf("kd %d: out of range", kd))
|
||||
}
|
||||
|
||||
if kx < 2 {
|
||||
panic(fmt.Errorf("kx %d: out of range", kx))
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
btDPool = sync.Pool{New: func() interface{} { return &d{} }}
|
||||
btEPool = btEpool{sync.Pool{New: func() interface{} { return &Enumerator{} }}}
|
||||
btTPool = btTpool{sync.Pool{New: func() interface{} { return &Tree{} }}}
|
||||
btXPool = sync.Pool{New: func() interface{} { return &x{} }}
|
||||
)
|
||||
|
||||
type btTpool struct{ sync.Pool }
|
||||
|
||||
func (p *btTpool) get(cmp Cmp) *Tree {
|
||||
x := p.Get().(*Tree)
|
||||
x.cmp = cmp
|
||||
return x
|
||||
}
|
||||
|
||||
type btEpool struct{ sync.Pool }
|
||||
|
||||
func (p *btEpool) get(err error, hit bool, i int, k interface{} /*K*/, q *d, t *Tree, ver int64) *Enumerator {
|
||||
x := p.Get().(*Enumerator)
|
||||
x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver
|
||||
return x
|
||||
}
|
||||
|
||||
type (
|
||||
// Cmp compares a and b. Return value is:
|
||||
//
|
||||
// < 0 if a < b
|
||||
// 0 if a == b
|
||||
// > 0 if a > b
|
||||
//
|
||||
Cmp func(a, b interface{} /*K*/) int
|
||||
|
||||
d struct { // data page
|
||||
c int
|
||||
d [2*kd + 1]de
|
||||
n *d
|
||||
p *d
|
||||
}
|
||||
|
||||
de struct { // d element
|
||||
k interface{} /*K*/
|
||||
v interface{} /*V*/
|
||||
}
|
||||
|
||||
// Enumerator captures the state of enumerating a tree. It is returned
|
||||
// from the Seek* methods. The enumerator is aware of any mutations
|
||||
// made to the tree in the process of enumerating it and automatically
|
||||
// resumes the enumeration at the proper key, if possible.
|
||||
//
|
||||
// However, once an Enumerator returns io.EOF to signal "no more
|
||||
// items", it does no more attempt to "resync" on tree mutation(s). In
|
||||
// other words, io.EOF from an Enumerator is "sticky" (idempotent).
|
||||
Enumerator struct {
|
||||
err error
|
||||
hit bool
|
||||
i int
|
||||
k interface{} /*K*/
|
||||
q *d
|
||||
t *Tree
|
||||
ver int64
|
||||
}
|
||||
|
||||
// Tree is a B+tree.
|
||||
Tree struct {
|
||||
c int
|
||||
cmp Cmp
|
||||
first *d
|
||||
last *d
|
||||
r interface{}
|
||||
ver int64
|
||||
}
|
||||
|
||||
xe struct { // x element
|
||||
ch interface{}
|
||||
k interface{} /*K*/
|
||||
}
|
||||
|
||||
x struct { // index page
|
||||
c int
|
||||
x [2*kx + 2]xe
|
||||
}
|
||||
)
|
||||
|
||||
var ( // R/O zero values
|
||||
zd d
|
||||
zde de
|
||||
ze Enumerator
|
||||
zk interface{} /*K*/
|
||||
zt Tree
|
||||
zx x
|
||||
zxe xe
|
||||
)
|
||||
|
||||
func clr(q interface{}) {
|
||||
switch x := q.(type) {
|
||||
case *x:
|
||||
for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn
|
||||
clr(x.x[i].ch)
|
||||
}
|
||||
*x = zx
|
||||
btXPool.Put(x)
|
||||
case *d:
|
||||
*x = zd
|
||||
btDPool.Put(x)
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- x
|
||||
|
||||
func newX(ch0 interface{}) *x {
|
||||
r := btXPool.Get().(*x)
|
||||
r.x[0].ch = ch0
|
||||
return r
|
||||
}
|
||||
|
||||
func (q *x) extract(i int) {
|
||||
q.c--
|
||||
if i < q.c {
|
||||
copy(q.x[i:], q.x[i+1:q.c+1])
|
||||
q.x[q.c].ch = q.x[q.c+1].ch
|
||||
q.x[q.c].k = zk // GC
|
||||
q.x[q.c+1] = zxe // GC
|
||||
}
|
||||
}
|
||||
|
||||
func (q *x) insert(i int, k interface{} /*K*/, ch interface{}) *x {
|
||||
c := q.c
|
||||
if i < c {
|
||||
q.x[c+1].ch = q.x[c].ch
|
||||
copy(q.x[i+2:], q.x[i+1:c])
|
||||
q.x[i+1].k = q.x[i].k
|
||||
}
|
||||
c++
|
||||
q.c = c
|
||||
q.x[i].k = k
|
||||
q.x[i+1].ch = ch
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *x) siblings(i int) (l, r *d) {
|
||||
if i >= 0 {
|
||||
if i > 0 {
|
||||
l = q.x[i-1].ch.(*d)
|
||||
}
|
||||
if i < q.c {
|
||||
r = q.x[i+1].ch.(*d)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- d
|
||||
|
||||
func (l *d) mvL(r *d, c int) {
|
||||
copy(l.d[l.c:], r.d[:c])
|
||||
copy(r.d[:], r.d[c:r.c])
|
||||
l.c += c
|
||||
r.c -= c
|
||||
}
|
||||
|
||||
func (l *d) mvR(r *d, c int) {
|
||||
copy(r.d[c:], r.d[:r.c])
|
||||
copy(r.d[:c], l.d[l.c-c:])
|
||||
r.c += c
|
||||
l.c -= c
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- Tree
|
||||
|
||||
// TreeNew returns a newly created, empty Tree. The compare function is used
|
||||
// for key collation.
|
||||
func TreeNew(cmp Cmp) *Tree {
|
||||
return btTPool.get(cmp)
|
||||
}
|
||||
|
||||
// Clear removes all K/V pairs from the tree.
|
||||
func (t *Tree) Clear() {
|
||||
if t.r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
clr(t.r)
|
||||
t.c, t.first, t.last, t.r = 0, nil, nil, nil
|
||||
t.ver++
|
||||
}
|
||||
|
||||
// Close performs Clear and recycles t to a pool for possible later reuse. No
|
||||
// references to t should exist or such references must not be used afterwards.
|
||||
func (t *Tree) Close() {
|
||||
t.Clear()
|
||||
*t = zt
|
||||
btTPool.Put(t)
|
||||
}
|
||||
|
||||
func (t *Tree) cat(p *x, q, r *d, pi int) {
|
||||
t.ver++
|
||||
q.mvL(r, r.c)
|
||||
if r.n != nil {
|
||||
r.n.p = q
|
||||
} else {
|
||||
t.last = q
|
||||
}
|
||||
q.n = r.n
|
||||
*r = zd
|
||||
btDPool.Put(r)
|
||||
if p.c > 1 {
|
||||
p.extract(pi)
|
||||
p.x[pi].ch = q
|
||||
return
|
||||
}
|
||||
|
||||
switch x := t.r.(type) {
|
||||
case *x:
|
||||
*x = zx
|
||||
btXPool.Put(x)
|
||||
case *d:
|
||||
*x = zd
|
||||
btDPool.Put(x)
|
||||
}
|
||||
t.r = q
|
||||
}
|
||||
|
||||
func (t *Tree) catX(p, q, r *x, pi int) {
|
||||
t.ver++
|
||||
q.x[q.c].k = p.x[pi].k
|
||||
copy(q.x[q.c+1:], r.x[:r.c])
|
||||
q.c += r.c + 1
|
||||
q.x[q.c].ch = r.x[r.c].ch
|
||||
*r = zx
|
||||
btXPool.Put(r)
|
||||
if p.c > 1 {
|
||||
p.c--
|
||||
pc := p.c
|
||||
if pi < pc {
|
||||
p.x[pi].k = p.x[pi+1].k
|
||||
copy(p.x[pi+1:], p.x[pi+2:pc+1])
|
||||
p.x[pc].ch = p.x[pc+1].ch
|
||||
p.x[pc].k = zk // GC
|
||||
p.x[pc+1].ch = nil // GC
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch x := t.r.(type) {
|
||||
case *x:
|
||||
*x = zx
|
||||
btXPool.Put(x)
|
||||
case *d:
|
||||
*x = zd
|
||||
btDPool.Put(x)
|
||||
}
|
||||
t.r = q
|
||||
}
|
||||
|
||||
// Delete removes the k's KV pair, if it exists, in which case Delete returns
|
||||
// true.
|
||||
func (t *Tree) Delete(k interface{} /*K*/) (ok bool) {
|
||||
pi := -1
|
||||
var p *x
|
||||
q := t.r
|
||||
if q == nil {
|
||||
return 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
|
||||
}
|
||||
|
||||
if q != t.r {
|
||||
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)
|
||||
}
|
||||
pi = i
|
||||
p = x
|
||||
q = x.x[i].ch
|
||||
case *d:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) extract(q *d, i int) { // (r interface{} /*V*/) {
|
||||
t.ver++
|
||||
//r = q.d[i].v // prepared for Extract
|
||||
q.c--
|
||||
if i < q.c {
|
||||
copy(q.d[i:], q.d[i+1:q.c+1])
|
||||
}
|
||||
q.d[q.c] = zde // GC
|
||||
t.c--
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Tree) find(q interface{}, k interface{} /*K*/) (i int, ok bool) {
|
||||
var mk interface{} /*K*/
|
||||
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 := t.cmp(k, mk); {
|
||||
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 := t.cmp(k, mk); {
|
||||
case cmp > 0:
|
||||
l = m + 1
|
||||
case cmp == 0:
|
||||
return m, true
|
||||
default:
|
||||
h = m - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return l, 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 interface{} /*K*/, v interface{} /*V*/) {
|
||||
if q := t.first; q != nil {
|
||||
q := &q.d[0]
|
||||
k, v = q.k, q.v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value associated with k and true if it exists. Otherwise Get
|
||||
// returns (zero-value, false).
|
||||
func (t *Tree) Get(k interface{} /*K*/) (v interface{} /*V*/, ok bool) {
|
||||
q := t.r
|
||||
if q == nil {
|
||||
return
|
||||
}
|
||||
|
||||
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:
|
||||
q = x.x[i].ch
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) insert(q *d, i int, k interface{} /*K*/, v interface{} /*V*/) *d {
|
||||
t.ver++
|
||||
c := q.c
|
||||
if i < c {
|
||||
copy(q.d[i+1:], q.d[i:c])
|
||||
}
|
||||
c++
|
||||
q.c = c
|
||||
q.d[i].k, q.d[i].v = k, v
|
||||
t.c++
|
||||
return q
|
||||
}
|
||||
|
||||
// Last returns the last item of the tree in the key collating order, or
|
||||
// (zero-value, zero-value) if the tree is empty.
|
||||
func (t *Tree) Last() (k interface{} /*K*/, v interface{} /*V*/) {
|
||||
if q := t.last; q != nil {
|
||||
q := &q.d[q.c-1]
|
||||
k, v = q.k, q.v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Len returns the number of items in the tree.
|
||||
func (t *Tree) Len() int {
|
||||
return t.c
|
||||
}
|
||||
|
||||
func (t *Tree) overflow(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /*V*/) {
|
||||
t.ver++
|
||||
l, r := p.siblings(pi)
|
||||
|
||||
if l != nil && l.c < 2*kd && i != 0 {
|
||||
l.mvL(q, 1)
|
||||
t.insert(q, i-1, k, v)
|
||||
p.x[pi-1].k = q.d[0].k
|
||||
return
|
||||
}
|
||||
|
||||
if r != nil && r.c < 2*kd {
|
||||
if i < 2*kd {
|
||||
q.mvR(r, 1)
|
||||
t.insert(q, i, k, v)
|
||||
p.x[pi].k = r.d[0].k
|
||||
return
|
||||
}
|
||||
|
||||
t.insert(r, 0, k, v)
|
||||
p.x[pi].k = k
|
||||
return
|
||||
}
|
||||
|
||||
t.split(p, q, pi, i, k, v)
|
||||
}
|
||||
|
||||
// Seek returns an Enumerator positioned on an item such that k >= item's key.
|
||||
// ok reports if k == item.key The Enumerator's position is possibly after the
|
||||
// last item in the tree.
|
||||
func (t *Tree) Seek(k interface{} /*K*/) (e *Enumerator, ok bool) {
|
||||
q := t.r
|
||||
if q == nil {
|
||||
e = btEPool.get(nil, false, 0, k, nil, t, t.ver)
|
||||
return
|
||||
}
|
||||
|
||||
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:
|
||||
q = x.x[i].ch
|
||||
case *d:
|
||||
return btEPool.get(nil, ok, i, k, x, t, t.ver), false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SeekFirst returns an enumerator positioned on the first KV pair in the tree,
|
||||
// if any. For an empty tree, err == io.EOF is returned and e will be nil.
|
||||
func (t *Tree) SeekFirst() (e *Enumerator, err error) {
|
||||
q := t.first
|
||||
if q == nil {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return btEPool.get(nil, true, 0, q.d[0].k, q, t, t.ver), nil
|
||||
}
|
||||
|
||||
// SeekLast returns an enumerator positioned on the last KV pair in the tree,
|
||||
// if any. For an empty tree, err == io.EOF is returned and e will be nil.
|
||||
func (t *Tree) SeekLast() (e *Enumerator, err error) {
|
||||
q := t.last
|
||||
if q == nil {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return btEPool.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, t.ver), nil
|
||||
}
|
||||
|
||||
// Set sets the value associated with k.
|
||||
func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
|
||||
//dbg("--- PRE Set(%v, %v)\n%s", k, v, t.dump())
|
||||
//defer func() {
|
||||
// dbg("--- POST\n%s\n====\n", t.dump())
|
||||
//}()
|
||||
|
||||
pi := -1
|
||||
var p *x
|
||||
q := t.r
|
||||
if q == nil {
|
||||
z := t.insert(btDPool.Get().(*d), 0, k, v)
|
||||
t.r, t.first, t.last = z, z, z
|
||||
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
|
||||
}
|
||||
|
||||
switch x := q.(type) {
|
||||
case *x:
|
||||
if x.c > 2*kx {
|
||||
x, i = t.splitX(p, x, pi, i)
|
||||
}
|
||||
pi = i
|
||||
p = x
|
||||
q = x.x[i].ch
|
||||
case *d:
|
||||
switch {
|
||||
case x.c < 2*kd:
|
||||
t.insert(x, i, k, v)
|
||||
default:
|
||||
t.overflow(p, x, pi, i, k, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put combines Get and Set in a more efficient way where the tree is walked
|
||||
// only once. The upd(ater) receives (old-value, true) if a KV pair for k
|
||||
// exists or (zero-value, false) otherwise. It can then return a (new-value,
|
||||
// true) to create or overwrite the existing value in the KV pair, or
|
||||
// (whatever, false) if it decides not to create or not to update the value of
|
||||
// the KV pair.
|
||||
//
|
||||
// tree.Set(k, v) call conceptually equals calling
|
||||
//
|
||||
// tree.Put(k, func(interface{} /*K*/, bool){ return v, true })
|
||||
//
|
||||
// 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) {
|
||||
pi := -1
|
||||
var p *x
|
||||
q := t.r
|
||||
var newV interface{} /*V*/
|
||||
if q == nil {
|
||||
// new KV pair in empty tree
|
||||
newV, written = upd(newV, false)
|
||||
if !written {
|
||||
return
|
||||
}
|
||||
|
||||
z := t.insert(btDPool.Get().(*d), 0, k, newV)
|
||||
t.r, t.first, t.last = z, z, z
|
||||
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
|
||||
}
|
||||
|
||||
x.d[i].v = newV
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch x := q.(type) {
|
||||
case *x:
|
||||
if x.c > 2*kx {
|
||||
x, i = t.splitX(p, x, pi, i)
|
||||
}
|
||||
pi = i
|
||||
p = x
|
||||
q = x.x[i].ch
|
||||
case *d: // new KV pair
|
||||
newV, written = upd(newV, false)
|
||||
if !written {
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case x.c < 2*kd:
|
||||
t.insert(x, i, k, newV)
|
||||
default:
|
||||
t.overflow(p, x, pi, i, k, newV)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /*V*/) {
|
||||
t.ver++
|
||||
r := btDPool.Get().(*d)
|
||||
if q.n != nil {
|
||||
r.n = q.n
|
||||
r.n.p = r
|
||||
} else {
|
||||
t.last = r
|
||||
}
|
||||
q.n = r
|
||||
r.p = q
|
||||
|
||||
copy(r.d[:], q.d[kd:2*kd])
|
||||
for i := range q.d[kd:] {
|
||||
q.d[kd+i] = zde
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
t.insert(q, i, k, v)
|
||||
}
|
||||
|
||||
func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
|
||||
t.ver++
|
||||
r := btXPool.Get().(*x)
|
||||
copy(r.x[:], q.x[kx+1:])
|
||||
q.c = kx
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) underflow(p *x, q *d, pi int) {
|
||||
t.ver++
|
||||
l, r := p.siblings(pi)
|
||||
|
||||
if l != nil && l.c+q.c >= 2*kd {
|
||||
l.mvR(q, 1)
|
||||
p.x[pi-1].k = q.d[0].k
|
||||
return
|
||||
}
|
||||
|
||||
if r != nil && q.c+r.c >= 2*kd {
|
||||
q.mvL(r, 1)
|
||||
p.x[pi].k = r.d[0].k
|
||||
r.d[r.c] = zde // GC
|
||||
return
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
t.cat(p, l, q, pi-1)
|
||||
return
|
||||
}
|
||||
|
||||
t.cat(p, q, r, pi)
|
||||
}
|
||||
|
||||
func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
|
||||
t.ver++
|
||||
var l, r *x
|
||||
|
||||
if pi >= 0 {
|
||||
if pi > 0 {
|
||||
l = p.x[pi-1].ch.(*x)
|
||||
}
|
||||
if pi < p.c {
|
||||
r = p.x[pi+1].ch.(*x)
|
||||
}
|
||||
}
|
||||
|
||||
if l != nil && l.c > kx {
|
||||
q.x[q.c+1].ch = q.x[q.c].ch
|
||||
copy(q.x[1:], q.x[:q.c])
|
||||
q.x[0].ch = l.x[l.c].ch
|
||||
q.x[0].k = p.x[pi-1].k
|
||||
q.c++
|
||||
i++
|
||||
l.c--
|
||||
p.x[pi-1].k = l.x[l.c].k
|
||||
return q, i
|
||||
}
|
||||
|
||||
if r != nil && r.c > kx {
|
||||
q.x[q.c].k = p.x[pi].k
|
||||
q.c++
|
||||
q.x[q.c].ch = r.x[0].ch
|
||||
p.x[pi].k = r.x[0].k
|
||||
copy(r.x[:], r.x[1:r.c])
|
||||
r.c--
|
||||
rc := r.c
|
||||
r.x[rc].ch = r.x[rc+1].ch
|
||||
r.x[rc].k = zk
|
||||
r.x[rc+1].ch = nil
|
||||
return q, i
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
i += l.c + 1
|
||||
t.catX(p, l, q, pi-1)
|
||||
q = l
|
||||
return q, i
|
||||
}
|
||||
|
||||
t.catX(p, q, r, pi)
|
||||
return q, i
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- Enumerator
|
||||
|
||||
// Close recycles e to a pool for possible later reuse. No references to e
|
||||
// should exist or such references must not be used afterwards.
|
||||
func (e *Enumerator) Close() {
|
||||
*e = ze
|
||||
btEPool.Put(e)
|
||||
}
|
||||
|
||||
// Next returns the currently enumerated item, if it exists and moves to the
|
||||
// next item in the key collation order. If there is no item to return, err ==
|
||||
// io.EOF is returned.
|
||||
func (e *Enumerator) Next() (k interface{} /*K*/, v interface{} /*V*/, err error) {
|
||||
if err = e.err; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e.ver != e.t.ver {
|
||||
f, hit := e.t.Seek(e.k)
|
||||
if !e.hit && hit {
|
||||
if err = f.next(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*e = *f
|
||||
f.Close()
|
||||
}
|
||||
if e.q == nil {
|
||||
e.err, err = io.EOF, io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
if e.i >= e.q.c {
|
||||
if err = e.next(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i := e.q.d[e.i]
|
||||
k, v = i.k, i.v
|
||||
e.k, e.hit = k, false
|
||||
e.next()
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Enumerator) next() error {
|
||||
if e.q == nil {
|
||||
e.err = io.EOF
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
switch {
|
||||
case e.i < e.q.c-1:
|
||||
e.i++
|
||||
default:
|
||||
if e.q, e.i = e.q.n, 0; e.q == nil {
|
||||
e.err = io.EOF
|
||||
}
|
||||
}
|
||||
return e.err
|
||||
}
|
||||
|
||||
// Prev returns the currently enumerated item, if it exists and moves to the
|
||||
// previous item in the key collation order. If there is no item to return, err
|
||||
// == io.EOF is returned.
|
||||
func (e *Enumerator) Prev() (k interface{} /*K*/, v interface{} /*V*/, err error) {
|
||||
if err = e.err; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e.ver != e.t.ver {
|
||||
f, hit := e.t.Seek(e.k)
|
||||
if !e.hit && hit {
|
||||
if err = f.prev(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*e = *f
|
||||
f.Close()
|
||||
}
|
||||
if e.q == nil {
|
||||
e.err, err = io.EOF, io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
if e.i >= e.q.c {
|
||||
if err = e.next(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i := e.q.d[e.i]
|
||||
k, v = i.k, i.v
|
||||
e.k, e.hit = k, false
|
||||
e.prev()
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Enumerator) prev() error {
|
||||
if e.q == nil {
|
||||
e.err = io.EOF
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
switch {
|
||||
case e.i > 0:
|
||||
e.i--
|
||||
default:
|
||||
if e.q = e.q.p; e.q == nil {
|
||||
e.err = io.EOF
|
||||
break
|
||||
}
|
||||
|
||||
e.i = e.q.c - 1
|
||||
}
|
||||
return e.err
|
||||
}
|
53
vendor/github.com/cznic/b/doc.go
generated
vendored
Normal file
53
vendor/github.com/cznic/b/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2014 The b Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package b implements the B+tree flavor of a BTree.
|
||||
//
|
||||
// Changelog
|
||||
//
|
||||
// 2014-06-26: Lower GC presure by recycling things.
|
||||
//
|
||||
// 2014-04-18: Added new method Put.
|
||||
//
|
||||
// Generic types
|
||||
//
|
||||
// Keys and their associated values are interface{} typed, similar to all of
|
||||
// the containers in the standard library.
|
||||
//
|
||||
// Semiautomatic production of a type specific variant of this package is
|
||||
// supported via
|
||||
//
|
||||
// $ make generic
|
||||
//
|
||||
// This command will write to stdout a version of the btree.go file where every
|
||||
// key type occurrence is replaced by the word 'KEY' and every value type
|
||||
// occurrence is replaced by the word 'VALUE'. Then you have to replace these
|
||||
// tokens with your desired type(s), using any technique you're comfortable
|
||||
// with.
|
||||
//
|
||||
// This is how, for example, 'example/int.go' was created:
|
||||
//
|
||||
// $ mkdir example
|
||||
// $ make generic | sed -e 's/KEY/int/g' -e 's/VALUE/int/g' > example/int.go
|
||||
//
|
||||
// No other changes to int.go are necessary, it compiles just fine.
|
||||
//
|
||||
// Running the benchmarks for 1000 keys on a machine with Intel i5-4670 CPU @
|
||||
// 3.4GHz, Go release 1.4.2.
|
||||
//
|
||||
// $ go test -bench 1e3 example/all_test.go example/int.go
|
||||
// PASS
|
||||
// BenchmarkSetSeq1e3 10000 151620 ns/op
|
||||
// BenchmarkGetSeq1e3 10000 115354 ns/op
|
||||
// BenchmarkSetRnd1e3 5000 255865 ns/op
|
||||
// BenchmarkGetRnd1e3 10000 140466 ns/op
|
||||
// BenchmarkDelSeq1e3 10000 143860 ns/op
|
||||
// BenchmarkDelRnd1e3 10000 188228 ns/op
|
||||
// BenchmarkSeekSeq1e3 10000 156448 ns/op
|
||||
// BenchmarkSeekRnd1e3 10000 190587 ns/op
|
||||
// BenchmarkNext1e3 200000 9407 ns/op
|
||||
// BenchmarkPrev1e3 200000 9306 ns/op
|
||||
// ok command-line-arguments 26.369s
|
||||
// $
|
||||
package b
|
35
vendor/github.com/cznic/b/example/Makefile
generated
vendored
Normal file
35
vendor/github.com/cznic/b/example/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2014 The b Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
.PHONY: all todo clean cover mem
|
||||
|
||||
testbin=b.test
|
||||
|
||||
all: editor
|
||||
go build
|
||||
go vet
|
||||
make todo
|
||||
|
||||
editor:
|
||||
go fmt
|
||||
go test -i
|
||||
go test
|
||||
|
||||
mem:
|
||||
go test -c
|
||||
./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1
|
||||
go tool pprof --lines --web --alloc_space $(testbin) mem.out
|
||||
|
||||
todo:
|
||||
@grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true
|
||||
@grep -n TODO *.go || true
|
||||
@grep -n BUG *.go || true
|
||||
@grep -n println *.go || true
|
||||
|
||||
clean:
|
||||
@go clean
|
||||
rm -f *~
|
||||
|
||||
cover:
|
||||
t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t
|
1126
vendor/github.com/cznic/b/example/all_test.go
generated
vendored
Normal file
1126
vendor/github.com/cznic/b/example/all_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
929
vendor/github.com/cznic/b/example/int.go
generated
vendored
Normal file
929
vendor/github.com/cznic/b/example/int.go
generated
vendored
Normal file
|
@ -0,0 +1,929 @@
|
|||
// Copyright 2014 The b Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package b
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
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).
|
||||
)
|
||||
|
||||
func init() {
|
||||
if kd < 1 {
|
||||
panic(fmt.Errorf("kd %d: out of range", kd))
|
||||
}
|
||||
|
||||
if kx < 2 {
|
||||
panic(fmt.Errorf("kx %d: out of range", kx))
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
btDPool = sync.Pool{New: func() interface{} { return &d{} }}
|
||||
btEPool = btEpool{sync.Pool{New: func() interface{} { return &Enumerator{} }}}
|
||||
btTPool = btTpool{sync.Pool{New: func() interface{} { return &Tree{} }}}
|
||||
btXPool = sync.Pool{New: func() interface{} { return &x{} }}
|
||||
)
|
||||
|
||||
type btTpool struct{ sync.Pool }
|
||||
|
||||
func (p *btTpool) get(cmp Cmp) *Tree {
|
||||
x := p.Get().(*Tree)
|
||||
x.cmp = cmp
|
||||
return x
|
||||
}
|
||||
|
||||
type btEpool struct{ sync.Pool }
|
||||
|
||||
func (p *btEpool) get(err error, hit bool, i int, k int, q *d, t *Tree, ver int64) *Enumerator {
|
||||
x := p.Get().(*Enumerator)
|
||||
x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver
|
||||
return x
|
||||
}
|
||||
|
||||
type (
|
||||
// Cmp compares a and b. Return value is:
|
||||
//
|
||||
// < 0 if a < b
|
||||
// 0 if a == b
|
||||
// > 0 if a > b
|
||||
//
|
||||
Cmp func(a, b int) int
|
||||
|
||||
d struct { // data page
|
||||
c int
|
||||
d [2*kd + 1]de
|
||||
n *d
|
||||
p *d
|
||||
}
|
||||
|
||||
de struct { // d element
|
||||
k int
|
||||
v int
|
||||
}
|
||||
|
||||
// Enumerator captures the state of enumerating a tree. It is returned
|
||||
// from the Seek* methods. The enumerator is aware of any mutations
|
||||
// made to the tree in the process of enumerating it and automatically
|
||||
// resumes the enumeration at the proper key, if possible.
|
||||
//
|
||||
// However, once an Enumerator returns io.EOF to signal "no more
|
||||
// items", it does no more attempt to "resync" on tree mutation(s). In
|
||||
// other words, io.EOF from an Enumaretor is "sticky" (idempotent).
|
||||
Enumerator struct {
|
||||
err error
|
||||
hit bool
|
||||
i int
|
||||
k int
|
||||
q *d
|
||||
t *Tree
|
||||
ver int64
|
||||
}
|
||||
|
||||
// Tree is a B+tree.
|
||||
Tree struct {
|
||||
c int
|
||||
cmp Cmp
|
||||
first *d
|
||||
last *d
|
||||
r interface{}
|
||||
ver int64
|
||||
}
|
||||
|
||||
xe struct { // x element
|
||||
ch interface{}
|
||||
k int
|
||||
}
|
||||
|
||||
x struct { // index page
|
||||
c int
|
||||
x [2*kx + 2]xe
|
||||
}
|
||||
)
|
||||
|
||||
var ( // R/O zero values
|
||||
zd d
|
||||
zde de
|
||||
ze Enumerator
|
||||
zk int
|
||||
zt Tree
|
||||
zx x
|
||||
zxe xe
|
||||
)
|
||||
|
||||
func clr(q interface{}) {
|
||||
switch x := q.(type) {
|
||||
case *x:
|
||||
for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn
|
||||
clr(x.x[i].ch)
|
||||
}
|
||||
*x = zx
|
||||
btXPool.Put(x)
|
||||
case *d:
|
||||
*x = zd
|
||||
btDPool.Put(x)
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- x
|
||||
|
||||
func newX(ch0 interface{}) *x {
|
||||
r := btXPool.Get().(*x)
|
||||
r.x[0].ch = ch0
|
||||
return r
|
||||
}
|
||||
|
||||
func (q *x) extract(i int) {
|
||||
q.c--
|
||||
if i < q.c {
|
||||
copy(q.x[i:], q.x[i+1:q.c+1])
|
||||
q.x[q.c].ch = q.x[q.c+1].ch
|
||||
q.x[q.c].k = zk // GC
|
||||
q.x[q.c+1] = zxe // GC
|
||||
}
|
||||
}
|
||||
|
||||
func (q *x) insert(i int, k int, ch interface{}) *x {
|
||||
c := q.c
|
||||
if i < c {
|
||||
q.x[c+1].ch = q.x[c].ch
|
||||
copy(q.x[i+2:], q.x[i+1:c])
|
||||
q.x[i+1].k = q.x[i].k
|
||||
}
|
||||
c++
|
||||
q.c = c
|
||||
q.x[i].k = k
|
||||
q.x[i+1].ch = ch
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *x) siblings(i int) (l, r *d) {
|
||||
if i >= 0 {
|
||||
if i > 0 {
|
||||
l = q.x[i-1].ch.(*d)
|
||||
}
|
||||
if i < q.c {
|
||||
r = q.x[i+1].ch.(*d)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- d
|
||||
|
||||
func (l *d) mvL(r *d, c int) {
|
||||
copy(l.d[l.c:], r.d[:c])
|
||||
copy(r.d[:], r.d[c:r.c])
|
||||
l.c += c
|
||||
r.c -= c
|
||||
}
|
||||
|
||||
func (l *d) mvR(r *d, c int) {
|
||||
copy(r.d[c:], r.d[:r.c])
|
||||
copy(r.d[:c], l.d[l.c-c:])
|
||||
r.c += c
|
||||
l.c -= c
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- Tree
|
||||
|
||||
// TreeNew returns a newly created, empty Tree. The compare function is used
|
||||
// for key collation.
|
||||
func TreeNew(cmp Cmp) *Tree {
|
||||
return btTPool.get(cmp)
|
||||
}
|
||||
|
||||
// Clear removes all K/V pairs from the tree.
|
||||
func (t *Tree) Clear() {
|
||||
if t.r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
clr(t.r)
|
||||
t.c, t.first, t.last, t.r = 0, nil, nil, nil
|
||||
t.ver++
|
||||
}
|
||||
|
||||
// Close performs Clear and recycles t to a pool for possible later reuse. No
|
||||
// references to t should exist or such references must not be used afterwards.
|
||||
func (t *Tree) Close() {
|
||||
t.Clear()
|
||||
*t = zt
|
||||
btTPool.Put(t)
|
||||
}
|
||||
|
||||
func (t *Tree) cat(p *x, q, r *d, pi int) {
|
||||
t.ver++
|
||||
q.mvL(r, r.c)
|
||||
if r.n != nil {
|
||||
r.n.p = q
|
||||
} else {
|
||||
t.last = q
|
||||
}
|
||||
q.n = r.n
|
||||
*r = zd
|
||||
btDPool.Put(r)
|
||||
if p.c > 1 {
|
||||
p.extract(pi)
|
||||
p.x[pi].ch = q
|
||||
return
|
||||
}
|
||||
|
||||
switch x := t.r.(type) {
|
||||
case *x:
|
||||
*x = zx
|
||||
btXPool.Put(x)
|
||||
case *d:
|
||||
*x = zd
|
||||
btDPool.Put(x)
|
||||
}
|
||||
t.r = q
|
||||
}
|
||||
|
||||
func (t *Tree) catX(p, q, r *x, pi int) {
|
||||
t.ver++
|
||||
q.x[q.c].k = p.x[pi].k
|
||||
copy(q.x[q.c+1:], r.x[:r.c])
|
||||
q.c += r.c + 1
|
||||
q.x[q.c].ch = r.x[r.c].ch
|
||||
*r = zx
|
||||
btXPool.Put(r)
|
||||
if p.c > 1 {
|
||||
p.c--
|
||||
pc := p.c
|
||||
if pi < pc {
|
||||
p.x[pi].k = p.x[pi+1].k
|
||||
copy(p.x[pi+1:], p.x[pi+2:pc+1])
|
||||
p.x[pc].ch = p.x[pc+1].ch
|
||||
p.x[pc].k = zk // GC
|
||||
p.x[pc+1].ch = nil // GC
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch x := t.r.(type) {
|
||||
case *x:
|
||||
*x = zx
|
||||
btXPool.Put(x)
|
||||
case *d:
|
||||
*x = zd
|
||||
btDPool.Put(x)
|
||||
}
|
||||
t.r = q
|
||||
}
|
||||
|
||||
// Delete removes the k's KV pair, if it exists, in which case Delete returns
|
||||
// true.
|
||||
func (t *Tree) Delete(k int) (ok bool) {
|
||||
pi := -1
|
||||
var p *x
|
||||
q := t.r
|
||||
if q == nil {
|
||||
return 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
|
||||
}
|
||||
|
||||
if q != t.r {
|
||||
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)
|
||||
}
|
||||
pi = i
|
||||
p = x
|
||||
q = x.x[i].ch
|
||||
case *d:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) extract(q *d, i int) { // (r int) {
|
||||
t.ver++
|
||||
//r = q.d[i].v // prepared for Extract
|
||||
q.c--
|
||||
if i < q.c {
|
||||
copy(q.d[i:], q.d[i+1:q.c+1])
|
||||
}
|
||||
q.d[q.c] = zde // GC
|
||||
t.c--
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Tree) find(q interface{}, k int) (i int, ok bool) {
|
||||
var mk int
|
||||
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 := t.cmp(k, mk); {
|
||||
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 := t.cmp(k, mk); {
|
||||
case cmp > 0:
|
||||
l = m + 1
|
||||
case cmp == 0:
|
||||
return m, true
|
||||
default:
|
||||
h = m - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return l, 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 int, v int) {
|
||||
if q := t.first; q != nil {
|
||||
q := &q.d[0]
|
||||
k, v = q.k, q.v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value associated with k and true if it exists. Otherwise Get
|
||||
// returns (zero-value, false).
|
||||
func (t *Tree) Get(k int) (v int, ok bool) {
|
||||
q := t.r
|
||||
if q == nil {
|
||||
return
|
||||
}
|
||||
|
||||
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:
|
||||
q = x.x[i].ch
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) insert(q *d, i int, k int, v int) *d {
|
||||
t.ver++
|
||||
c := q.c
|
||||
if i < c {
|
||||
copy(q.d[i+1:], q.d[i:c])
|
||||
}
|
||||
c++
|
||||
q.c = c
|
||||
q.d[i].k, q.d[i].v = k, v
|
||||
t.c++
|
||||
return q
|
||||
}
|
||||
|
||||
// Last returns the last item of the tree in the key collating order, or
|
||||
// (zero-value, zero-value) if the tree is empty.
|
||||
func (t *Tree) Last() (k int, v int) {
|
||||
if q := t.last; q != nil {
|
||||
q := &q.d[q.c-1]
|
||||
k, v = q.k, q.v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Len returns the number of items in the tree.
|
||||
func (t *Tree) Len() int {
|
||||
return t.c
|
||||
}
|
||||
|
||||
func (t *Tree) overflow(p *x, q *d, pi, i int, k int, v int) {
|
||||
t.ver++
|
||||
l, r := p.siblings(pi)
|
||||
|
||||
if l != nil && l.c < 2*kd {
|
||||
l.mvL(q, 1)
|
||||
t.insert(q, i-1, k, v)
|
||||
p.x[pi-1].k = q.d[0].k
|
||||
return
|
||||
}
|
||||
|
||||
if r != nil && r.c < 2*kd {
|
||||
if i < 2*kd {
|
||||
q.mvR(r, 1)
|
||||
t.insert(q, i, k, v)
|
||||
p.x[pi].k = r.d[0].k
|
||||
return
|
||||
}
|
||||
|
||||
t.insert(r, 0, k, v)
|
||||
p.x[pi].k = k
|
||||
return
|
||||
}
|
||||
|
||||
t.split(p, q, pi, i, k, v)
|
||||
}
|
||||
|
||||
// Seek returns an Enumerator positioned on a an item such that k >= item's
|
||||
// key. ok reports if k == item.key The Enumerator's position is possibly
|
||||
// after the last item in the tree.
|
||||
func (t *Tree) Seek(k int) (e *Enumerator, ok bool) {
|
||||
q := t.r
|
||||
if q == nil {
|
||||
e = btEPool.get(nil, false, 0, k, nil, t, t.ver)
|
||||
return
|
||||
}
|
||||
|
||||
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:
|
||||
q = x.x[i].ch
|
||||
case *d:
|
||||
return btEPool.get(nil, ok, i, k, x, t, t.ver), false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SeekFirst returns an enumerator positioned on the first KV pair in the tree,
|
||||
// if any. For an empty tree, err == io.EOF is returned and e will be nil.
|
||||
func (t *Tree) SeekFirst() (e *Enumerator, err error) {
|
||||
q := t.first
|
||||
if q == nil {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return btEPool.get(nil, true, 0, q.d[0].k, q, t, t.ver), nil
|
||||
}
|
||||
|
||||
// SeekLast returns an enumerator positioned on the last KV pair in the tree,
|
||||
// if any. For an empty tree, err == io.EOF is returned and e will be nil.
|
||||
func (t *Tree) SeekLast() (e *Enumerator, err error) {
|
||||
q := t.last
|
||||
if q == nil {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return btEPool.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, t.ver), nil
|
||||
}
|
||||
|
||||
// Set sets the value associated with k.
|
||||
func (t *Tree) Set(k int, v int) {
|
||||
//dbg("--- PRE Set(%v, %v)\n%s", k, v, t.dump())
|
||||
//defer func() {
|
||||
// dbg("--- POST\n%s\n====\n", t.dump())
|
||||
//}()
|
||||
|
||||
pi := -1
|
||||
var p *x
|
||||
q := t.r
|
||||
if q == nil {
|
||||
z := t.insert(btDPool.Get().(*d), 0, k, v)
|
||||
t.r, t.first, t.last = z, z, z
|
||||
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
|
||||
}
|
||||
|
||||
switch x := q.(type) {
|
||||
case *x:
|
||||
if x.c > 2*kx {
|
||||
x, i = t.splitX(p, x, pi, i)
|
||||
}
|
||||
pi = i
|
||||
p = x
|
||||
q = x.x[i].ch
|
||||
case *d:
|
||||
switch {
|
||||
case x.c < 2*kd:
|
||||
t.insert(x, i, k, v)
|
||||
default:
|
||||
t.overflow(p, x, pi, i, k, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put combines Get and Set in a more efficient way where the tree is walked
|
||||
// only once. The upd(ater) receives (old-value, true) if a KV pair for k
|
||||
// exists or (zero-value, false) otherwise. It can then return a (new-value,
|
||||
// true) to create or overwrite the existing value in the KV pair, or
|
||||
// (whatever, false) if it decides not to create or not to update the value of
|
||||
// the KV pair.
|
||||
//
|
||||
// tree.Set(k, v) call conceptually equals calling
|
||||
//
|
||||
// tree.Put(k, func(int, bool){ return v, true })
|
||||
//
|
||||
// modulo the differing return values.
|
||||
func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)) (oldV int, written bool) {
|
||||
pi := -1
|
||||
var p *x
|
||||
q := t.r
|
||||
var newV int
|
||||
if q == nil {
|
||||
// new KV pair in empty tree
|
||||
newV, written = upd(newV, false)
|
||||
if !written {
|
||||
return
|
||||
}
|
||||
|
||||
z := t.insert(btDPool.Get().(*d), 0, k, newV)
|
||||
t.r, t.first, t.last = z, z, z
|
||||
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
|
||||
}
|
||||
|
||||
x.d[i].v = newV
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch x := q.(type) {
|
||||
case *x:
|
||||
if x.c > 2*kx {
|
||||
x, i = t.splitX(p, x, pi, i)
|
||||
}
|
||||
pi = i
|
||||
p = x
|
||||
q = x.x[i].ch
|
||||
case *d: // new KV pair
|
||||
newV, written = upd(newV, false)
|
||||
if !written {
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case x.c < 2*kd:
|
||||
t.insert(x, i, k, newV)
|
||||
default:
|
||||
t.overflow(p, x, pi, i, k, newV)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
|
||||
t.ver++
|
||||
r := btDPool.Get().(*d)
|
||||
if q.n != nil {
|
||||
r.n = q.n
|
||||
r.n.p = r
|
||||
} else {
|
||||
t.last = r
|
||||
}
|
||||
q.n = r
|
||||
r.p = q
|
||||
|
||||
copy(r.d[:], q.d[kd:2*kd])
|
||||
for i := range q.d[kd:] {
|
||||
q.d[kd+i] = zde
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
t.insert(q, i, k, v)
|
||||
}
|
||||
|
||||
func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
|
||||
t.ver++
|
||||
r := btXPool.Get().(*x)
|
||||
copy(r.x[:], q.x[kx+1:])
|
||||
q.c = kx
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) underflow(p *x, q *d, pi int) {
|
||||
t.ver++
|
||||
l, r := p.siblings(pi)
|
||||
|
||||
if l != nil && l.c+q.c >= 2*kd {
|
||||
l.mvR(q, 1)
|
||||
p.x[pi-1].k = q.d[0].k
|
||||
return
|
||||
}
|
||||
|
||||
if r != nil && q.c+r.c >= 2*kd {
|
||||
q.mvL(r, 1)
|
||||
p.x[pi].k = r.d[0].k
|
||||
r.d[r.c] = zde // GC
|
||||
return
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
t.cat(p, l, q, pi-1)
|
||||
return
|
||||
}
|
||||
|
||||
t.cat(p, q, r, pi)
|
||||
}
|
||||
|
||||
func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
|
||||
t.ver++
|
||||
var l, r *x
|
||||
|
||||
if pi >= 0 {
|
||||
if pi > 0 {
|
||||
l = p.x[pi-1].ch.(*x)
|
||||
}
|
||||
if pi < p.c {
|
||||
r = p.x[pi+1].ch.(*x)
|
||||
}
|
||||
}
|
||||
|
||||
if l != nil && l.c > kx {
|
||||
q.x[q.c+1].ch = q.x[q.c].ch
|
||||
copy(q.x[1:], q.x[:q.c])
|
||||
q.x[0].ch = l.x[l.c].ch
|
||||
q.x[0].k = p.x[pi-1].k
|
||||
q.c++
|
||||
i++
|
||||
l.c--
|
||||
p.x[pi-1].k = l.x[l.c].k
|
||||
return q, i
|
||||
}
|
||||
|
||||
if r != nil && r.c > kx {
|
||||
q.x[q.c].k = p.x[pi].k
|
||||
q.c++
|
||||
q.x[q.c].ch = r.x[0].ch
|
||||
p.x[pi].k = r.x[0].k
|
||||
copy(r.x[:], r.x[1:r.c])
|
||||
r.c--
|
||||
rc := r.c
|
||||
r.x[rc].ch = r.x[rc+1].ch
|
||||
r.x[rc].k = zk
|
||||
r.x[rc+1].ch = nil
|
||||
return q, i
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
i += l.c + 1
|
||||
t.catX(p, l, q, pi-1)
|
||||
q = l
|
||||
return q, i
|
||||
}
|
||||
|
||||
t.catX(p, q, r, pi)
|
||||
return q, i
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- Enumerator
|
||||
|
||||
// Close recycles e to a pool for possible later reuse. No references to e
|
||||
// should exist or such references must not be used afterwards.
|
||||
func (e *Enumerator) Close() {
|
||||
*e = ze
|
||||
btEPool.Put(e)
|
||||
}
|
||||
|
||||
// Next returns the currently enumerated item, if it exists and moves to the
|
||||
// next item in the key collation order. If there is no item to return, err ==
|
||||
// io.EOF is returned.
|
||||
func (e *Enumerator) Next() (k int, v int, err error) {
|
||||
if err = e.err; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e.ver != e.t.ver {
|
||||
f, hit := e.t.Seek(e.k)
|
||||
if !e.hit && hit {
|
||||
if err = f.next(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*e = *f
|
||||
f.Close()
|
||||
}
|
||||
if e.q == nil {
|
||||
e.err, err = io.EOF, io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
if e.i >= e.q.c {
|
||||
if err = e.next(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i := e.q.d[e.i]
|
||||
k, v = i.k, i.v
|
||||
e.k, e.hit = k, false
|
||||
e.next()
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Enumerator) next() error {
|
||||
if e.q == nil {
|
||||
e.err = io.EOF
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
switch {
|
||||
case e.i < e.q.c-1:
|
||||
e.i++
|
||||
default:
|
||||
if e.q, e.i = e.q.n, 0; e.q == nil {
|
||||
e.err = io.EOF
|
||||
}
|
||||
}
|
||||
return e.err
|
||||
}
|
||||
|
||||
// Prev returns the currently enumerated item, if it exists and moves to the
|
||||
// previous item in the key collation order. If there is no item to return, err
|
||||
// == io.EOF is returned.
|
||||
func (e *Enumerator) Prev() (k int, v int, err error) {
|
||||
if err = e.err; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e.ver != e.t.ver {
|
||||
f, hit := e.t.Seek(e.k)
|
||||
if !e.hit && hit {
|
||||
if err = f.prev(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*e = *f
|
||||
f.Close()
|
||||
}
|
||||
if e.q == nil {
|
||||
e.err, err = io.EOF, io.EOF
|
||||
return
|
||||
}
|
||||
|
||||
if e.i >= e.q.c {
|
||||
if err = e.next(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i := e.q.d[e.i]
|
||||
k, v = i.k, i.v
|
||||
e.k, e.hit = k, false
|
||||
e.prev()
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Enumerator) prev() error {
|
||||
if e.q == nil {
|
||||
e.err = io.EOF
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
switch {
|
||||
case e.i > 0:
|
||||
e.i--
|
||||
default:
|
||||
if e.q = e.q.p; e.q == nil {
|
||||
e.err = io.EOF
|
||||
break
|
||||
}
|
||||
|
||||
e.i = e.q.c - 1
|
||||
}
|
||||
return e.err
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue