Commit 5a1179fd authored by Jan Mercl's avatar Jan Mercl

Overhaul benchmarks

parent 0496ce60
......@@ -140,11 +140,7 @@ func TestGet0(t *testing.T) {
t.Fatal(g, e)
}
v, ok := r.Get(42)
if v != nil {
t.Fatal(v)
}
_, ok := r.Get(42)
if ok {
t.Fatal(ok)
}
......@@ -228,67 +224,152 @@ func TestSetGet1(t *testing.T) {
t.Fatal(i, k, v, ok)
}
if v == nil {
t.Fatal(i, k)
}
if g, e := v.(int), k^x; g != e {
t.Fatal(i, g, e)
}
k |= 1
v, ok = r.Get(k)
_, ok = r.Get(k)
if ok {
t.Fatal(i, k)
}
if v != nil {
t.Fatal(i, k)
}
}
}
}
func BenchmarkSetSeq(b *testing.B) {
r := TreeNew(cmp)
debug.FreeOSMemory()
func BenchmarkSetSeq1e2(b *testing.B) {
benchmarkSetSeq(b, 1e2)
}
func BenchmarkSetSeq1e3(b *testing.B) {
benchmarkSetSeq(b, 1e3)
}
func BenchmarkSetSeq1e4(b *testing.B) {
benchmarkSetSeq(b, 1e4)
}
func BenchmarkSetSeq1e5(b *testing.B) {
benchmarkSetSeq(b, 1e5)
}
func BenchmarkSetSeq1e6(b *testing.B) {
benchmarkSetSeq(b, 1e6)
}
func benchmarkSetSeq(b *testing.B, n int) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Set(i, i)
b.StopTimer()
r := TreeNew(cmp)
debug.FreeOSMemory()
b.StartTimer()
for j := 0; j < n; j++ {
r.Set(j, j)
}
}
b.StopTimer()
}
func BenchmarkGetSeq1e2(b *testing.B) {
benchmarkGetSeq(b, 1e2)
}
func BenchmarkGetSeq1e3(b *testing.B) {
benchmarkGetSeq(b, 1e3)
}
func BenchmarkGetSeq1e4(b *testing.B) {
benchmarkGetSeq(b, 1e4)
}
func BenchmarkGetSeq1e5(b *testing.B) {
benchmarkGetSeq(b, 1e5)
}
func BenchmarkGetSeq1e6(b *testing.B) {
benchmarkGetSeq(b, 1e6)
}
func BenchmarkSetRnd(b *testing.B) {
func benchmarkGetSeq(b *testing.B, n int) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
for i := range a {
a[i] = rng.Next()
for i := 0; i < n; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Set(v, 0)
for i := 0; i < b.N; i++ {
for j := 0; j < n; j++ {
r.Get(j)
}
}
b.StopTimer()
}
func BenchmarkGetSeq(b *testing.B) {
r := TreeNew(cmp)
for i := 0; i < b.N; i++ {
r.Set(i, i)
func BenchmarkSetRnd1e2(b *testing.B) {
benchmarkSetRnd(b, 1e2)
}
func BenchmarkSetRnd1e3(b *testing.B) {
benchmarkSetRnd(b, 1e3)
}
func BenchmarkSetRnd1e4(b *testing.B) {
benchmarkSetRnd(b, 1e4)
}
func BenchmarkSetRnd1e5(b *testing.B) {
benchmarkSetRnd(b, 1e5)
}
func BenchmarkSetRnd1e6(b *testing.B) {
benchmarkSetRnd(b, 1e6)
}
func benchmarkSetRnd(b *testing.B, n int) {
rng := rng()
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Get(i)
b.StopTimer()
r := TreeNew(cmp)
debug.FreeOSMemory()
b.StartTimer()
for _, v := range a {
r.Set(v, 0)
}
}
b.StopTimer()
}
func BenchmarkGetRnd1e2(b *testing.B) {
benchmarkGetRnd(b, 1e2)
}
func BenchmarkGetRnd1e3(b *testing.B) {
benchmarkGetRnd(b, 1e3)
}
func BenchmarkGetRnd1e4(b *testing.B) {
benchmarkGetRnd(b, 1e4)
}
func BenchmarkGetRnd1e5(b *testing.B) {
benchmarkGetRnd(b, 1e5)
}
func BenchmarkGetRnd(b *testing.B) {
func BenchmarkGetRnd1e6(b *testing.B) {
benchmarkGetRnd(b, 1e6)
}
func benchmarkGetRnd(b *testing.B, n int) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
......@@ -297,9 +378,12 @@ func BenchmarkGetRnd(b *testing.B) {
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Get(v)
for i := 0; i < b.N; i++ {
for _, v := range a {
r.Get(v)
}
}
b.StopTimer()
}
func TestSetGet2(t *testing.T) {
......@@ -325,24 +409,15 @@ func TestSetGet2(t *testing.T) {
t.Fatal(i, k, v, ok)
}
if v == nil {
t.Fatal(i, k)
}
if g, e := v.(int), k^x; g != e {
t.Fatal(i, g, e)
}
k |= 1
v, ok = r.Get(k)
_, ok = r.Get(k)
if ok {
t.Fatal(i, k)
}
if v != nil {
t.Fatal(i, k)
}
}
}
}
......@@ -367,10 +442,6 @@ func TestSetGet3(t *testing.T) {
t.Fatal(j)
}
if v == nil {
t.Fatal(j)
}
if g, e := v.(int), j; g != e {
t.Fatal(g, e)
}
......@@ -487,33 +558,83 @@ func TestDelete1(t *testing.T) {
}
}
func BenchmarkDelSeq(b *testing.B) {
r := TreeNew(cmp)
for i := 0; i < b.N; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
func benchmarkDelSeq1e2(b *testing.B) {
benchmarkDelSeq(b, 1e2)
}
func benchmarkDelSeq1e3(b *testing.B) {
benchmarkDelSeq(b, 1e3)
}
func benchmarkDelSeq1e4(b *testing.B) {
benchmarkDelSeq(b, 1e4)
}
func benchmarkDelSeq1e5(b *testing.B) {
benchmarkDelSeq(b, 1e5)
}
func benchmarkDelSeq1e6(b *testing.B) {
benchmarkDelSeq(b, 1e6)
}
func benchmarkDelSeq(b *testing.B, n int) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Delete(i)
b.StopTimer()
r := TreeNew(cmp)
for i := 0; i < n; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
b.StartTimer()
for j := 0; j < n; j++ {
r.Delete(j)
}
}
b.StopTimer()
}
func BenchmarkDelRnd(b *testing.B) {
r := TreeNew(cmp)
func BenchmarkDelRnd1e2(b *testing.B) {
benchmarkDelRnd(b, 1e2)
}
func BenchmarkDelRnd1e3(b *testing.B) {
benchmarkDelRnd(b, 1e3)
}
func BenchmarkDelRnd1e4(b *testing.B) {
benchmarkDelRnd(b, 1e4)
}
func BenchmarkDelRnd1e5(b *testing.B) {
benchmarkDelRnd(b, 1e5)
}
func BenchmarkDelRnd1e6(b *testing.B) {
benchmarkDelRnd(b, 1e6)
}
func benchmarkDelRnd(b *testing.B, n int) {
rng := rng()
a := make([]int, b.N)
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Delete(v)
for i := 0; i < b.N; i++ {
b.StopTimer()
r := TreeNew(cmp)
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.StartTimer()
for _, v := range a {
r.Delete(v)
}
}
b.StopTimer()
}
func TestDelete2(t *testing.T) {
......@@ -568,7 +689,6 @@ func TestEnumeratorNext(t *testing.T) {
r.Set(30, 300)
for verChange := 0; verChange < 16; verChange++ {
//t.Logf("Seek %d", test.k)
en, hit := r.Seek(test.k)
if g, e := hit, test.hit; g != e {
......@@ -578,7 +698,6 @@ func TestEnumeratorNext(t *testing.T) {
j := 0
for {
if verChange&(1<<uint(j)) != 0 {
//t.Log("version change")
r.Set(20, 200)
}
......@@ -591,7 +710,6 @@ func TestEnumeratorNext(t *testing.T) {
break
}
//t.Logf("Next -> %v: %v", k, v)
if j >= len(up) {
t.Fatal(i, j, verChange)
}
......@@ -641,7 +759,6 @@ func TestEnumeratorPrev(t *testing.T) {
r.Set(30, 300)
for verChange := 0; verChange < 16; verChange++ {
//t.Logf("Seek %d", test.k)
en, hit := r.Seek(test.k)
if g, e := hit, test.hit; g != e {
......@@ -651,7 +768,6 @@ func TestEnumeratorPrev(t *testing.T) {
j := 0
for {
if verChange&(1<<uint(j)) != 0 {
//t.Log("version change")
r.Set(20, 200)
}
......@@ -664,7 +780,6 @@ func TestEnumeratorPrev(t *testing.T) {
break
}
//t.Logf("Prev -> %v: %v", k, v)
if j >= len(dn) {
t.Fatal(i, j, verChange)
}
......@@ -689,22 +804,66 @@ func TestEnumeratorPrev(t *testing.T) {
}
}
func BenchmarkSeekSeq(b *testing.B) {
t := TreeNew(cmp)
for i := 0; i < b.N; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
func BenchmarkSeekSeq1e2(b *testing.B) {
benchmarkSeekSeq(b, 1e2)
}
func BenchmarkSeekSeq1e3(b *testing.B) {
benchmarkSeekSeq(b, 1e3)
}
func BenchmarkSeekSeq1e4(b *testing.B) {
benchmarkSeekSeq(b, 1e4)
}
func BenchmarkSeekSeq1e5(b *testing.B) {
benchmarkSeekSeq(b, 1e5)
}
func BenchmarkSeekSeq1e6(b *testing.B) {
benchmarkSeekSeq(b, 1e6)
}
func benchmarkSeekSeq(b *testing.B, n int) {
for i := 0; i < b.N; i++ {
t.Seek(i)
b.StopTimer()
t := TreeNew(cmp)
for j := 0; j < n; j++ {
t.Set(j, 0)
}
debug.FreeOSMemory()
b.StartTimer()
for j := 0; j < n; j++ {
t.Seek(j)
}
}
b.StopTimer()
}
func BenchmarkSeekRnd1e2(b *testing.B) {
benchmarkSeekRnd(b, 1e2)
}
func BenchmarkSeekRnd1e3(b *testing.B) {
benchmarkSeekRnd(b, 1e3)
}
func BenchmarkSeekRnd1e4(b *testing.B) {
benchmarkSeekRnd(b, 1e4)
}
func BenchmarkSeekRnd(b *testing.B) {
func BenchmarkSeekRnd1e5(b *testing.B) {
benchmarkSeekRnd(b, 1e5)
}
func BenchmarkSeekRnd1e6(b *testing.B) {
benchmarkSeekRnd(b, 1e6)
}
func benchmarkSeekRnd(b *testing.B, n int) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
......@@ -713,15 +872,36 @@ func BenchmarkSeekRnd(b *testing.B) {
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Seek(v)
for i := 0; i < b.N; i++ {
for _, v := range a {
r.Seek(v)
}
}
}
func BenchmarkNext1e2(b *testing.B) {
benchmarkNext(b, 1e2)
}
func BenchmarkNext1e3(b *testing.B) {
const N = 1e3
benchmarkNext(b, 1e3)
}
func BenchmarkNext1e4(b *testing.B) {
benchmarkNext(b, 1e4)
}
func BenchmarkNext1e5(b *testing.B) {
benchmarkNext(b, 1e5)
}
func BenchmarkNext1e6(b *testing.B) {
benchmarkNext(b, 1e6)
}
func benchmarkNext(b *testing.B, n int) {
t := TreeNew(cmp)
for i := 0; i < N; i++ {
for i := 0; i < n; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
......@@ -731,23 +911,43 @@ func BenchmarkNext1e3(b *testing.B) {
if err != nil {
b.Fatal(err)
}
n := 0
m := 0
for {
if _, _, err = en.Next(); err != nil {
break
}
n++
m++
}
if n != N {
b.Fatal(n)
if m != n {
b.Fatal(m)
}
}
}
func BenchmarkPrev1e2(b *testing.B) {
benchmarkPrev(b, 1e2)
}
func BenchmarkPrev1e3(b *testing.B) {
const N = 1e3
benchmarkPrev(b, 1e3)
}
func BenchmarkPrev1e4(b *testing.B) {
benchmarkPrev(b, 1e4)
}
func BenchmarkPrev1e5(b *testing.B) {
benchmarkPrev(b, 1e5)
}
func BenchmarkPrev1e6(b *testing.B) {
benchmarkPrev(b, 1e6)
}
func benchmarkPrev(b *testing.B, n int) {
t := TreeNew(cmp)
for i := 0; i < N; i++ {
for i := 0; i < n; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
......@@ -757,15 +957,16 @@ func BenchmarkPrev1e3(b *testing.B) {
if err != nil {
b.Fatal(err)
}
n := 0
m := 0
for {
if _, _, err = en.Prev(); err != nil {
break
}
n++
m++
}
if n != N {
b.Fatal(n)
if m != n {
b.Fatal(m)
}
}
}
......
......@@ -35,56 +35,22 @@
// $ make generic | sed -e 's/key/int/g' -e 's/value/int/g' > example/int.go
//
// No other changes to int.go are (strictly) necessary, it compiles just fine.
// In a next step, benchmarks from all_test.go were copied into
// example/bench_test.go without any changes. A comparator is defined in
// bench_test.go like this:
//
// func cmp(a, b int) int {
// return a - b
// }
// Running the benchmarks for 1000 keys on a machine with Intel X5450 CPU @ 3
// GHz, Go release 1.3.
//
// Running the benchmarks on a machine with Intel X5450 CPU @ 3 GHz:
//
// Go release (1.1.2)
//
// $ go test -bench . example/bench_test.go example/int.go
// testing: warning: no tests to run
// PASS
// BenchmarkSetSeq 5000000 590 ns/op
// BenchmarkSetRnd 1000000 1530 ns/op
// BenchmarkGetSeq 10000000 373 ns/op
// BenchmarkGetRnd 2000000 1109 ns/op
// BenchmarkDelSeq 5000000 672 ns/op
// BenchmarkDelRnd 1000000 1275 ns/op
// BenchmarkSeekSeq 5000000 552 ns/op
// BenchmarkSeekRnd 1000000 1108 ns/op
// BenchmarkNext1e3 200000 13414 ns/op
// BenchmarkPrev1e3 200000 13215 ns/op
// ok command-line-arguments 51.372s
// $
//
// Go 1.2rc2
//
// $ go test -bench . example/bench_test.go example/int.go
// testing: warning: no tests to run
// $ go test -bench 1e3 example/all_test.go example/int.go
// PASS
// BenchmarkSetSeq 5000000 535 ns/op
// BenchmarkSetRnd 1000000 1428 ns/op
// BenchmarkGetSeq 10000000 376 ns/op
// BenchmarkGetRnd 2000000 1105 ns/op
// BenchmarkDelSeq 5000000 618 ns/op
// BenchmarkDelRnd 1000000 1213 ns/op
// BenchmarkSeekSeq 5000000 538 ns/op
// BenchmarkSeekRnd 1000000 1088 ns/op
// BenchmarkNext1e3 200000 13410 ns/op
// BenchmarkPrev1e3 200000 13528 ns/op
// ok command-line-arguments 48.823s
// $
//
// Note that the Next and Prev benchmarks enumerate 1000 items (KV pairs), so
// getting the next or previous iterated item is performed in about 13-14 ns.
// This is the nice O(1) property of B+trees usually not found in other tree
// types.
// BenchmarkSetSeq1e3 10000 263951 ns/op
// BenchmarkGetSeq1e3 10000 154410 ns/op
// BenchmarkSetRnd1e3 5000 392690 ns/op
// BenchmarkGetRnd1e3 10000 181776 ns/op
// BenchmarkDelRnd1e3 5000 323795 ns/op
// BenchmarkSeekSeq1e3 10000 235939 ns/op
// BenchmarkSeekRnd1e3 5000 299997 ns/op
// BenchmarkNext1e3 200000 14202 ns/op
// BenchmarkPrev1e3 200000 13842 ns/op
// ok command-line-arguments 30.620s
package b
import (
......
.PHONY: all todo clean cover
all: editor
go build
go vet
make todo
editor:
go fmt
go test -i
go test
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
// Copyright 2013 The Go 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 (
"io"
"math"
"runtime/debug"
"testing"
"github.com/cznic/fileutil"
"github.com/cznic/mathutil"
)
func rng() *mathutil.FC32 {
x, err := mathutil.NewFC32(math.MinInt32/4, math.MaxInt32/4, false)
if err != nil {
panic(err)
}
return x
}
func cmp(a, b int) int {
return a - b
}
func TestGet0(t *testing.T) {
r := TreeNew(cmp)
if g, e := r.Len(), 0; g != e {
t.Fatal(g, e)
}
_, ok := r.Get(42)
if ok {
t.Fatal(ok)
}
}
func TestSetGet0(t *testing.T) {
r := TreeNew(cmp)
set := r.Set
set(42, 314)
if g, e := r.Len(), 1; g != e {
t.Fatal(g, e)
}
v, ok := r.Get(42)
if !ok {
t.Fatal(ok)
}
if g, e := v, 314; g != e {
t.Fatal(g, e)
}
set(42, 278)
if g, e := r.Len(), 1; g != e {
t.Fatal(g, e)
}
v, ok = r.Get(42)
if !ok {
t.Fatal(ok)
}
if g, e := v, 278; g != e {
t.Fatal(g, e)
}
set(420, 50)
if g, e := r.Len(), 2; g != e {
t.Fatal(g, e)
}
v, ok = r.Get(42)
if !ok {
t.Fatal(ok)
}
if g, e := v, 278; g != e {
t.Fatal(g, e)
}
v, ok = r.Get(420)
if !ok {
t.Fatal(ok)
}
if g, e := v, 50; g != e {
t.Fatal(g, e)
}
}
func TestSetGet1(t *testing.T) {
const N = 90000
for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} {
r := TreeNew(cmp)
set := r.Set
a := make([]int, N)
for i := range a {
a[i] = (i ^ x) << 1
}
for i, k := range a {
set(k, k^x)
if g, e := r.Len(), i+1; g != e {
t.Fatal(i, g, e)
}
}
for i, k := range a {
v, ok := r.Get(k)
if !ok {
t.Fatal(i, k, v, ok)
}
if g, e := v, k^x; g != e {
t.Fatal(i, g, e)
}
k |= 1
_, ok = r.Get(k)
if ok {
t.Fatal(i, k)
}
}
}
}
func BenchmarkSetSeq1e2(b *testing.B) {
benchmarkSetSeq(b, 1e2)
}
func BenchmarkSetSeq1e3(b *testing.B) {
benchmarkSetSeq(b, 1e3)
}
func BenchmarkSetSeq1e4(b *testing.B) {
benchmarkSetSeq(b, 1e4)
}
func BenchmarkSetSeq1e5(b *testing.B) {
benchmarkSetSeq(b, 1e5)
}
func BenchmarkSetSeq1e6(b *testing.B) {
benchmarkSetSeq(b, 1e6)
}
func benchmarkSetSeq(b *testing.B, n int) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
r := TreeNew(cmp)
debug.FreeOSMemory()
b.StartTimer()
for j := 0; j < n; j++ {
r.Set(j, j)
}
}
b.StopTimer()
}
func BenchmarkGetSeq1e2(b *testing.B) {
benchmarkGetSeq(b, 1e2)
}
func BenchmarkGetSeq1e3(b *testing.B) {
benchmarkGetSeq(b, 1e3)
}
func BenchmarkGetSeq1e4(b *testing.B) {
benchmarkGetSeq(b, 1e4)
}
func BenchmarkGetSeq1e5(b *testing.B) {
benchmarkGetSeq(b, 1e5)
}
func BenchmarkGetSeq1e6(b *testing.B) {
benchmarkGetSeq(b, 1e6)
}
func benchmarkGetSeq(b *testing.B, n int) {
r := TreeNew(cmp)
for i := 0; i < n; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < n; j++ {
r.Get(j)
}
}
b.StopTimer()
}
func BenchmarkSetRnd1e2(b *testing.B) {
benchmarkSetRnd(b, 1e2)
}
func BenchmarkSetRnd1e3(b *testing.B) {
benchmarkSetRnd(b, 1e3)
}
func BenchmarkSetRnd1e4(b *testing.B) {
benchmarkSetRnd(b, 1e4)
}
func BenchmarkSetRnd1e5(b *testing.B) {
benchmarkSetRnd(b, 1e5)
}
func BenchmarkSetRnd1e6(b *testing.B) {
benchmarkSetRnd(b, 1e6)
}
func benchmarkSetRnd(b *testing.B, n int) {
rng := rng()
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
r := TreeNew(cmp)
debug.FreeOSMemory()
b.StartTimer()
for _, v := range a {
r.Set(v, 0)
}
}
b.StopTimer()
}
func BenchmarkGetRnd1e2(b *testing.B) {
benchmarkGetRnd(b, 1e2)
}
func BenchmarkGetRnd1e3(b *testing.B) {
benchmarkGetRnd(b, 1e3)
}
func BenchmarkGetRnd1e4(b *testing.B) {
benchmarkGetRnd(b, 1e4)
}
func BenchmarkGetRnd1e5(b *testing.B) {
benchmarkGetRnd(b, 1e5)
}
func BenchmarkGetRnd1e6(b *testing.B) {
benchmarkGetRnd(b, 1e6)
}
func benchmarkGetRnd(b *testing.B, n int) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, v := range a {
r.Get(v)
}
}
b.StopTimer()
}
func TestSetGet2(t *testing.T) {
const N = 70000
for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} {
r := TreeNew(cmp)
set := r.Set
a := make([]int, N)
rng := rng()
for i := range a {
a[i] = (rng.Next() ^ x) << 1
}
for i, k := range a {
set(k, k^x)
if g, e := r.Len(), i+1; g != e {
t.Fatal(i, x, g, e)
}
}
for i, k := range a {
v, ok := r.Get(k)
if !ok {
t.Fatal(i, k, v, ok)
}
if g, e := v, k^x; g != e {
t.Fatal(i, g, e)
}
k |= 1
_, ok = r.Get(k)
if ok {
t.Fatal(i, k)
}
}
}
}
func TestSetGet3(t *testing.T) {
r := TreeNew(cmp)
set := r.Set
var i int
for i = 0; ; i++ {
set(i, -i)
if _, ok := r.r.(*x); ok {
break
}
}
for j := 0; j <= i; j++ {
set(j, j)
}
for j := 0; j <= i; j++ {
v, ok := r.Get(j)
if !ok {
t.Fatal(j)
}
if g, e := v, j; g != e {
t.Fatal(g, e)
}
}
}
func TestDelete0(t *testing.T) {
r := TreeNew(cmp)
if ok := r.Delete(0); ok {
t.Fatal(ok)
}
if g, e := r.Len(), 0; g != e {
t.Fatal(g, e)
}
r.Set(0, 0)
if ok := r.Delete(1); ok {
t.Fatal(ok)
}
if g, e := r.Len(), 1; g != e {
t.Fatal(g, e)
}
if ok := r.Delete(0); !ok {
t.Fatal(ok)
}
if g, e := r.Len(), 0; g != e {
t.Fatal(g, e)
}
if ok := r.Delete(0); ok {
t.Fatal(ok)
}
r.Set(0, 0)
r.Set(1, 1)
if ok := r.Delete(1); !ok {
t.Fatal(ok)
}
if g, e := r.Len(), 1; g != e {
t.Fatal(g, e)
}
if ok := r.Delete(1); ok {
t.Fatal(ok)
}
if ok := r.Delete(0); !ok {
t.Fatal(ok)
}
if g, e := r.Len(), 0; g != e {
t.Fatal(g, e)
}
if ok := r.Delete(0); ok {
t.Fatal(ok)
}
r.Set(0, 0)
r.Set(1, 1)
if ok := r.Delete(0); !ok {
t.Fatal(ok)
}
if g, e := r.Len(), 1; g != e {
t.Fatal(g, e)
}
if ok := r.Delete(0); ok {
t.Fatal(ok)
}
if ok := r.Delete(1); !ok {
t.Fatal(ok)
}
if g, e := r.Len(), 0; g != e {
t.Fatal(g, e)
}
if ok := r.Delete(1); ok {
t.Fatal(ok)
}
}
func TestDelete1(t *testing.T) {
const N = 100000
for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} {
r := TreeNew(cmp)
set := r.Set
a := make([]int, N)
for i := range a {
a[i] = (i ^ x) << 1
}
for _, k := range a {
set(k, 0)
}
for i, k := range a {
ok := r.Delete(k)
if !ok {
t.Fatal(i, x, k)
}
if g, e := r.Len(), N-i-1; g != e {
t.Fatal(i, g, e)
}
}
}
}
func benchmarkDelSeq1e2(b *testing.B) {
benchmarkDelSeq(b, 1e2)
}
func benchmarkDelSeq1e3(b *testing.B) {
benchmarkDelSeq(b, 1e3)
}
func benchmarkDelSeq1e4(b *testing.B) {
benchmarkDelSeq(b, 1e4)
}
func benchmarkDelSeq1e5(b *testing.B) {
benchmarkDelSeq(b, 1e5)
}
func benchmarkDelSeq1e6(b *testing.B) {
benchmarkDelSeq(b, 1e6)
}
func benchmarkDelSeq(b *testing.B, n int) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
r := TreeNew(cmp)
for i := 0; i < n; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
b.StartTimer()
for j := 0; j < n; j++ {
r.Delete(j)
}
}
b.StopTimer()
}
func BenchmarkDelRnd1e2(b *testing.B) {
benchmarkDelRnd(b, 1e2)
}
func BenchmarkDelRnd1e3(b *testing.B) {
benchmarkDelRnd(b, 1e3)
}
func BenchmarkDelRnd1e4(b *testing.B) {
benchmarkDelRnd(b, 1e4)
}
func BenchmarkDelRnd1e5(b *testing.B) {
benchmarkDelRnd(b, 1e5)
}
func BenchmarkDelRnd1e6(b *testing.B) {
benchmarkDelRnd(b, 1e6)
}
func benchmarkDelRnd(b *testing.B, n int) {
rng := rng()
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
r := TreeNew(cmp)
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.StartTimer()
for _, v := range a {
r.Delete(v)
}
}
b.StopTimer()
}
func TestDelete2(t *testing.T) {
const N = 80000
for _, x := range []int{0, -1, 0x555555, 0xaaaaaa, 0x314259} {
r := TreeNew(cmp)
set := r.Set
a := make([]int, N)
rng := rng()
for i := range a {
a[i] = (rng.Next() ^ x) << 1
}
for _, k := range a {
set(k, 0)
}
for i, k := range a {
ok := r.Delete(k)
if !ok {
t.Fatal(i, x, k)
}
if g, e := r.Len(), N-i-1; g != e {
t.Fatal(i, g, e)
}
}
}
}
func TestEnumeratorNext(t *testing.T) {
// seeking within 3 keys: 10, 20, 30
table := []struct {
k int
hit bool
keys []int
}{
{5, false, []int{10, 20, 30}},
{10, true, []int{10, 20, 30}},
{15, false, []int{20, 30}},
{20, true, []int{20, 30}},
{25, false, []int{30}},
{30, true, []int{30}},
{35, false, []int{}},
}
for i, test := range table {
up := test.keys
r := TreeNew(cmp)
r.Set(10, 100)
r.Set(20, 200)
r.Set(30, 300)
for verChange := 0; verChange < 16; verChange++ {
en, hit := r.Seek(test.k)
if g, e := hit, test.hit; g != e {
t.Fatal(i, g, e)
}
j := 0
for {
if verChange&(1<<uint(j)) != 0 {
r.Set(20, 200)
}
k, v, err := en.Next()
if err != nil {
if !fileutil.IsEOF(err) {
t.Fatal(i, err)
}
break
}
if j >= len(up) {
t.Fatal(i, j, verChange)
}
if g, e := k, up[j]; g != e {
t.Fatal(i, j, verChange, g, e)
}
if g, e := v, 10*up[j]; g != e {
t.Fatal(i, g, e)
}
j++
}
if g, e := j, len(up); g != e {
t.Fatal(i, j, g, e)
}
}
}
}
func TestEnumeratorPrev(t *testing.T) {
// seeking within 3 keys: 10, 20, 30
table := []struct {
k int
hit bool
keys []int
}{
{5, false, []int{10}},
{10, true, []int{10}},
{15, false, []int{20, 10}},
{20, true, []int{20, 10}},
{25, false, []int{30, 20, 10}},
{30, true, []int{30, 20, 10}},
{35, false, []int{}},
}
for i, test := range table {
dn := test.keys
r := TreeNew(cmp)
r.Set(10, 100)
r.Set(20, 200)
r.Set(30, 300)
for verChange := 0; verChange < 16; verChange++ {
en, hit := r.Seek(test.k)
if g, e := hit, test.hit; g != e {
t.Fatal(i, g, e)
}
j := 0
for {
if verChange&(1<<uint(j)) != 0 {
r.Set(20, 200)
}
k, v, err := en.Prev()
if err != nil {
if !fileutil.IsEOF(err) {
t.Fatal(i, err)
}
break
}
if j >= len(dn) {
t.Fatal(i, j, verChange)
}
if g, e := k, dn[j]; g != e {
t.Fatal(i, j, verChange, g, e)
}
if g, e := v, 10*dn[j]; g != e {
t.Fatal(i, g, e)
}
j++
}
if g, e := j, len(dn); g != e {
t.Fatal(i, j, g, e)
}
}
}
}
func BenchmarkSeekSeq1e2(b *testing.B) {
benchmarkSeekSeq(b, 1e2)
}
func BenchmarkSeekSeq1e3(b *testing.B) {
benchmarkSeekSeq(b, 1e3)
}
func BenchmarkSeekSeq1e4(b *testing.B) {
benchmarkSeekSeq(b, 1e4)
}
func BenchmarkSeekSeq1e5(b *testing.B) {
benchmarkSeekSeq(b, 1e5)
}
func BenchmarkSeekSeq1e6(b *testing.B) {
benchmarkSeekSeq(b, 1e6)
}
func benchmarkSeekSeq(b *testing.B, n int) {
for i := 0; i < b.N; i++ {
b.StopTimer()
t := TreeNew(cmp)
for j := 0; j < n; j++ {
t.Set(j, 0)
}
debug.FreeOSMemory()
b.StartTimer()
for j := 0; j < n; j++ {
t.Seek(j)
}
}
b.StopTimer()
}
func BenchmarkSeekRnd1e2(b *testing.B) {
benchmarkSeekRnd(b, 1e2)
}
func BenchmarkSeekRnd1e3(b *testing.B) {
benchmarkSeekRnd(b, 1e3)
}
func BenchmarkSeekRnd1e4(b *testing.B) {
benchmarkSeekRnd(b, 1e4)
}
func BenchmarkSeekRnd1e5(b *testing.B) {
benchmarkSeekRnd(b, 1e5)
}
func BenchmarkSeekRnd1e6(b *testing.B) {
benchmarkSeekRnd(b, 1e6)
}
func benchmarkSeekRnd(b *testing.B, n int) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, n)
for i := range a {
a[i] = rng.Next()
}
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, v := range a {
r.Seek(v)
}
}
}
func BenchmarkNext1e2(b *testing.B) {
benchmarkNext(b, 1e2)
}
func BenchmarkNext1e3(b *testing.B) {
benchmarkNext(b, 1e3)
}
func BenchmarkNext1e4(b *testing.B) {
benchmarkNext(b, 1e4)
}
func BenchmarkNext1e5(b *testing.B) {
benchmarkNext(b, 1e5)
}
func BenchmarkNext1e6(b *testing.B) {
benchmarkNext(b, 1e6)
}
func benchmarkNext(b *testing.B, n int) {
t := TreeNew(cmp)
for i := 0; i < n; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
en, err := t.SeekFirst()
if err != nil {
b.Fatal(err)
}
m := 0
for {
if _, _, err = en.Next(); err != nil {
break
}
m++
}
if m != n {
b.Fatal(m)
}
}
}
func BenchmarkPrev1e2(b *testing.B) {
benchmarkPrev(b, 1e2)
}
func BenchmarkPrev1e3(b *testing.B) {
benchmarkPrev(b, 1e3)
}
func BenchmarkPrev1e4(b *testing.B) {
benchmarkPrev(b, 1e4)
}
func BenchmarkPrev1e5(b *testing.B) {
benchmarkPrev(b, 1e5)
}
func BenchmarkPrev1e6(b *testing.B) {
benchmarkPrev(b, 1e6)
}
func benchmarkPrev(b *testing.B, n int) {
t := TreeNew(cmp)
for i := 0; i < n; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
en, err := t.SeekLast()
if err != nil {
b.Fatal(err)
}
m := 0
for {
if _, _, err = en.Prev(); err != nil {
break
}
m++
}
if m != n {
b.Fatal(m)
}
}
}
func TestSeekFirst0(t *testing.T) {
b := TreeNew(cmp)
_, err := b.SeekFirst()
if g, e := err, io.EOF; g != e {
t.Fatal(g, e)
}
}
func TestSeekFirst1(t *testing.T) {
b := TreeNew(cmp)
b.Set(1, 10)
en, err := b.SeekFirst()
if err != nil {
t.Fatal(err)
}
k, v, err := en.Next()
if k != 1 || v != 10 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Next()
if err == nil {
t.Fatal(k, v, err)
}
}
func TestSeekFirst2(t *testing.T) {
b := TreeNew(cmp)
b.Set(1, 10)
b.Set(2, 20)
en, err := b.SeekFirst()
if err != nil {
t.Fatal(err)
}
k, v, err := en.Next()
if k != 1 || v != 10 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Next()
if k != 2 || v != 20 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Next()
if err == nil {
t.Fatal(k, v, err)
}
}
func TestSeekFirst3(t *testing.T) {
b := TreeNew(cmp)
b.Set(2, 20)
b.Set(3, 30)
b.Set(1, 10)
en, err := b.SeekFirst()
if err != nil {
t.Fatal(err)
}
k, v, err := en.Next()
if k != 1 || v != 10 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Next()
if k != 2 || v != 20 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Next()
if k != 3 || v != 30 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Next()
if err == nil {
t.Fatal(k, v, err)
}
}
func TestSeekLast0(t *testing.T) {
b := TreeNew(cmp)
_, err := b.SeekLast()
if g, e := err, io.EOF; g != e {
t.Fatal(g, e)
}
}
func TestSeekLast1(t *testing.T) {
b := TreeNew(cmp)
b.Set(1, 10)
en, err := b.SeekLast()
if err != nil {
t.Fatal(err)
}
k, v, err := en.Prev()
if k != 1 || v != 10 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Prev()
if err == nil {
t.Fatal(k, v, err)
}
}
func TestSeekLast2(t *testing.T) {
b := TreeNew(cmp)
b.Set(1, 10)
b.Set(2, 20)
en, err := b.SeekLast()
if err != nil {
t.Fatal(err)
}
k, v, err := en.Prev()
if k != 2 || v != 20 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Prev()
if k != 1 || v != 10 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Prev()
if err == nil {
t.Fatal(k, v, err)
}
}
func TestSeekLast3(t *testing.T) {
b := TreeNew(cmp)
b.Set(2, 20)
b.Set(3, 30)
b.Set(1, 10)
en, err := b.SeekLast()
if err != nil {
t.Fatal(err)
}
k, v, err := en.Prev()
if k != 3 || v != 30 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Prev()
if k != 2 || v != 20 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Prev()
if k != 1 || v != 10 || err != nil {
t.Fatal(k, v, err)
}
k, v, err = en.Prev()
if err == nil {
t.Fatal(k, v, err)
}
}
func TestPut(t *testing.T) {
tab := []struct {
pre []int // even index: K, odd index: V
newK int // Put(newK, ...
oldV int // Put()->oldV
exists bool // upd(exists)
write bool // upd()->write
post []int // even index: K, odd index: V
}{
// 0
{
[]int{},
1, 0, false, false,
[]int{},
},
{
[]int{},
1, 0, false, true,
[]int{1, -1},
},
{
[]int{1, 10},
0, 0, false, false,
[]int{1, 10},
},
{
[]int{1, 10},
0, 0, false, true,
[]int{0, -1, 1, 10},
},
{
[]int{1, 10},
1, 10, true, false,
[]int{1, 10},
},
// 5
{
[]int{1, 10},
1, 10, true, true,
[]int{1, -1},
},
{
[]int{1, 10},
2, 0, false, false,
[]int{1, 10},
},
{
[]int{1, 10},
2, 0, false, true,
[]int{1, 10, 2, -1},
},
}
for iTest, test := range tab {
tr := TreeNew(cmp)
for i := 0; i < len(test.pre); i += 2 {
k, v := test.pre[i], test.pre[i+1]
tr.Set(k, v)
}
oldV, written := tr.Put(test.newK, func(old int, exists bool) (newV int, write bool) {
if g, e := exists, test.exists; g != e {
t.Fatal(iTest, g, e)
}
if exists {
if g, e := old, test.oldV; g != e {
t.Fatal(iTest, g, e)
}
}
return -1, test.write
})
if test.exists {
if g, e := oldV, test.oldV; g != e {
t.Fatal(iTest, g, e)
}
}
if g, e := written, test.write; g != e {
t.Fatal(iTest, g, e)
}
n := len(test.post)
en, err := tr.SeekFirst()
if err != nil {
if n == 0 && err == io.EOF {
continue
}
t.Fatal(iTest, err)
}
for i := 0; i < len(test.post); i += 2 {
k, v, err := en.Next()
if err != nil {
t.Fatal(iTest, err)
}
if g, e := k, test.post[i]; g != e {
t.Fatal(iTest, g, e)
}
if g, e := v, test.post[i+1]; g != e {
t.Fatal(iTest, g, e)
}
}
_, _, err = en.Next()
if g, e := err, io.EOF; g != e {
t.Fatal(iTest, g, e)
}
}
}
// Copyright 2013 The Go 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 (
"math"
"runtime/debug"
"testing"
"github.com/cznic/mathutil"
)
func cmp(a, b int) int {
return a - b
}
func rng() *mathutil.FC32 {
x, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, false)
if err != nil {
panic(err)
}
return x
}
func BenchmarkSetSeq(b *testing.B) {
r := TreeNew(cmp)
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Set(i, i)
}
}
func BenchmarkSetRnd(b *testing.B) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
for i := range a {
a[i] = rng.Next()
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Set(v, 0)
}
}
func BenchmarkGetSeq(b *testing.B) {
r := TreeNew(cmp)
for i := 0; i < b.N; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Get(i)
}
}
func BenchmarkGetRnd(b *testing.B) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
for i := range a {
a[i] = rng.Next()
}
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Get(v)
}
}
func BenchmarkDelSeq(b *testing.B) {
r := TreeNew(cmp)
for i := 0; i < b.N; i++ {
r.Set(i, i)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Delete(i)
}
}
func BenchmarkDelRnd(b *testing.B) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
for i := range a {
a[i] = rng.Next()
}
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Delete(v)
}
}
func BenchmarkSeekSeq(b *testing.B) {
t := TreeNew(cmp)
for i := 0; i < b.N; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
t.Seek(i)
}
}
func BenchmarkSeekRnd(b *testing.B) {
r := TreeNew(cmp)
rng := rng()
a := make([]int, b.N)
for i := range a {
a[i] = rng.Next()
}
for _, v := range a {
r.Set(v, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for _, v := range a {
r.Seek(v)
}
}
func BenchmarkNext1e3(b *testing.B) {
const N = 1e3
t := TreeNew(cmp)
for i := 0; i < N; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
en, err := t.SeekFirst()
if err != nil {
b.Fatal(err)
}
n := 0
for {
if _, _, err = en.Next(); err != nil {
break
}
n++
}
if n != N {
b.Fatal(n)
}
}
}
func BenchmarkPrev1e3(b *testing.B) {
const N = 1e3
t := TreeNew(cmp)
for i := 0; i < N; i++ {
t.Set(i, 0)
}
debug.FreeOSMemory()
b.ResetTimer()
for i := 0; i < b.N; i++ {
en, err := t.SeekLast()
if err != nil {
b.Fatal(err)
}
n := 0
for {
if _, _, err = en.Prev(); err != nil {
break
}
n++
}
if n != N {
b.Fatal(n)
}
}
}
......@@ -2,27 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package b implements a B+tree.
//
// Keys and their associated values are interface{} typed, similarly to all of
// the containers in the standard library.
//
// Semiautomatic production of a type specific variant of this package is
// supported via
//
// $ make generic
//
// Performing it will write to stdout a version of the btree.go file where
// every key type occurrence is replaced by the word 'key' (written in all
// CAPS) and every value type occurrence is replaced by the word 'value'
// (written in all CAPS). Then you have to replace theses strings 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
//
// Package b implements an int->int B+tree.
package b
import (
......@@ -233,8 +213,8 @@ func (t *Tree) catX(p, q, r *x, pi int) {
t.r = q //TODO recycle r
}
//Delete removes the k's KV pair, if it exists, in which case Delete returns
//true.
// 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
......@@ -341,7 +321,7 @@ func (t *Tree) find(q interface{}, k int) (i int, ok bool) {
}
// First returns the first item of the tree in the key collating order, or
// (nil, nil) if the tree is empty.
// (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]
......@@ -351,7 +331,7 @@ func (t *Tree) First() (k int, v int) {
}
// Get returns the value associated with k and true if it exists. Otherwise Get
// returns (nil, false).
// returns (zero-value, false).
func (t *Tree) Get(k int) (v int, ok bool) {
q := t.r
if q == nil {
......@@ -390,8 +370,8 @@ func (t *Tree) insert(q *d, i int, k int, v int) *d {
return q
}
// Last returns the last item of the tree in the key collating order, or (nil,
// nil) if the tree is empty.
// 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]
......@@ -525,6 +505,84 @@ func (t *Tree) Set(k int, v int) {
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) conceptually equals
//
// tree.Put(k, func(k, v []byte){ return v, true }([]byte, bool))
//
// 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 {
for {
i, ok := t.find(q, k)
if ok {
switch x := q.(type) {
case *x:
oldV = x.x[i].sep.d[0].v
newV, written = upd(oldV, true)
if !written {
return
}
x.x[i].sep.d[0].v = newV
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 {
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
}
}
}
// new KV pair in empty tree
newV, written = upd(newV, false)
if !written {
return
}
z := t.insert(&d{}, 0, k, newV)
t.r, t.first, t.last = z, z, z
return
}
func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
t.ver++
r := &d{}
......
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