Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
b
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
b
Commits
9c2ebb9b
Commit
9c2ebb9b
authored
Jun 26, 2013
by
Jan Mercl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More benchmarks, more documentation
parent
be48a068
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1062 additions
and
3 deletions
+1062
-3
all_test.go
all_test.go
+81
-0
btree.go
btree.go
+45
-3
example/bench_test.go
example/bench_test.go
+188
-0
example/int.go
example/int.go
+748
-0
No files found.
all_test.go
View file @
9c2ebb9b
...
...
@@ -683,3 +683,84 @@ 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
()
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
)
}
}
}
btree.go
View file @
9c2ebb9b
...
...
@@ -17,6 +17,47 @@
// 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
// $
// $ # Note: the command bellow must be actually written using the words
// $ # 'key' and 'value' in all CAPS. The proper form is avoided in this
// $ # documentation to not confuse any text replacement mechanism.
// $
// $ 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 on a machine with Intel X5450 CPU @ 3 GHz:
//
// $ 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
// $
//
// 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 ns. This
// is the nice O(1) property of B+trees, usually not found in other tree types.
package
b
import
(
...
...
@@ -33,9 +74,10 @@ const (
type
(
// Cmp compares a and b. Return value is:
//
// -1 if a < b
// 0 if a == b
// +1 if a > b
// < 0 if a < b
// 0 if a == b
// > 0 if a > b
//
Cmp
func
(
a
,
b
interface
{}
/*K*/
)
int
d
struct
{
// data page
...
...
example/bench_test.go
0 → 100644
View file @
9c2ebb9b
// 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
)
}
}
}
example/int.go
0 → 100644
View file @
9c2ebb9b
// 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 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/int/int/g' -e 's/int/int/g' > example/int.go
//
package
b
import
(
"io"
)
//TODO check vs orig initialize/finalize
const
(
kx
=
128
//TODO benchmark tune this number if using custom key/value type(s).
kd
=
64
//TODO benchmark tune this number if using custom key/value type(s).
)
type
(
// Cmp compares a and b. Return value is:
//
// -1 if a < b
// 0 if a == b
// +1 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
{}
sep
*
d
}
x
struct
{
// index page
c
int
x
[
2
*
kx
+
2
]
xe
}
)
var
(
// R/O zero values
zd
d
zde
de
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
// GC
case
*
d
:
*
x
=
zd
// GC
}
}
// -------------------------------------------------------------------------- x
func
newX
(
ch0
interface
{})
*
x
{
r
:=
&
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
]
.
sep
=
nil
// GC
q
.
x
[
q
.
c
+
1
]
=
zxe
// GC
}
}
func
(
q
*
x
)
insert
(
i
int
,
d
*
d
,
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
]
.
sep
=
q
.
x
[
i
]
.
sep
}
c
++
q
.
c
=
c
q
.
x
[
i
]
.
sep
=
d
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
&
Tree
{
cmp
:
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
++
}
func
(
t
*
Tree
)
cat
(
p
*
x
,
q
,
r
*
d
,
pi
int
)
{
q
.
mvL
(
r
,
r
.
c
)
if
r
.
n
!=
nil
{
r
.
n
.
p
=
q
}
else
{
t
.
last
=
q
}
q
.
n
=
r
.
n
//TODO recycle r
if
p
.
c
>
1
{
p
.
extract
(
pi
)
p
.
x
[
pi
]
.
ch
=
q
}
else
{
//TODO recycle r
t
.
r
=
q
}
}
func
(
t
*
Tree
)
catX
(
p
,
q
,
r
*
x
,
pi
int
)
{
q
.
x
[
q
.
c
]
.
sep
=
p
.
x
[
pi
]
.
sep
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
//TODO recycle r
if
p
.
c
>
1
{
p
.
c
--
pc
:=
p
.
c
if
pi
<
pc
{
p
.
x
[
pi
]
.
sep
=
p
.
x
[
pi
+
1
]
.
sep
copy
(
p
.
x
[
pi
+
1
:
],
p
.
x
[
pi
+
2
:
pc
+
1
])
p
.
x
[
pc
]
.
ch
=
p
.
x
[
pc
+
1
]
.
ch
p
.
x
[
pc
]
.
sep
=
nil
// GC
p
.
x
[
pc
+
1
]
.
ch
=
nil
// GC
}
return
}
t
.
r
=
q
//TODO recycle r
}
//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
}
for
{
var
i
int
i
,
ok
=
t
.
find
(
q
,
k
)
if
ok
{
switch
x
:=
q
.
(
type
)
{
case
*
x
:
dp
:=
x
.
x
[
i
]
.
sep
switch
{
case
dp
.
c
>
kd
:
t
.
extract
(
dp
,
0
)
default
:
if
x
.
c
<
kx
&&
q
!=
t
.
r
{
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
)
t
.
ver
++
if
x
.
c
>=
kd
{
return
}
if
q
!=
t
.
r
{
t
.
underflow
(
p
,
x
,
pi
)
}
else
if
t
.
c
==
0
{
t
.
Clear
()
}
}
return
}
switch
x
:=
q
.
(
type
)
{
case
*
x
:
if
x
.
c
<
kx
&&
q
!=
t
.
r
{
t
.
underflowX
(
p
,
&
x
,
pi
,
&
i
)
}
pi
=
i
p
=
x
q
=
x
.
x
[
i
]
.
ch
case
*
d
:
return
}
}
}
func
(
t
*
Tree
)
extract
(
q
*
d
,
i
int
)
{
// (r int) {
//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
]
.
sep
.
d
[
0
]
.
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
// (nil, nil) 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 (nil, 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
:
return
x
.
x
[
i
]
.
sep
.
d
[
0
]
.
v
,
true
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
{
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 (nil,
// nil) 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
)
{
l
,
r
:=
p
.
siblings
(
pi
)
if
l
!=
nil
&&
l
.
c
<
2
*
kd
{
l
.
mvL
(
q
,
1
)
t
.
insert
(
q
,
i
-
1
,
k
,
v
)
return
}
if
r
!=
nil
&&
r
.
c
<
2
*
kd
{
if
i
<
2
*
kd
{
q
.
mvR
(
r
,
1
)
t
.
insert
(
q
,
i
,
k
,
v
)
}
else
{
t
.
insert
(
r
,
0
,
k
,
v
)
}
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
=
&
Enumerator
{
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
:
e
=
&
Enumerator
{
nil
,
ok
,
0
,
k
,
x
.
x
[
i
]
.
sep
,
t
,
t
.
ver
}
return
case
*
d
:
e
=
&
Enumerator
{
nil
,
ok
,
i
,
k
,
x
,
t
,
t
.
ver
}
return
}
}
switch
x
:=
q
.
(
type
)
{
case
*
x
:
q
=
x
.
x
[
i
]
.
ch
case
*
d
:
e
=
&
Enumerator
{
nil
,
ok
,
i
,
k
,
x
,
t
,
t
.
ver
}
return
}
}
}
// 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
&
Enumerator
{
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
&
Enumerator
{
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
)
{
pi
:=
-
1
var
p
*
x
q
:=
t
.
r
if
q
!=
nil
{
for
{
i
,
ok
:=
t
.
find
(
q
,
k
)
if
ok
{
switch
x
:=
q
.
(
type
)
{
case
*
x
:
x
.
x
[
i
]
.
sep
.
d
[
0
]
.
v
=
v
case
*
d
:
x
.
d
[
i
]
.
v
=
v
}
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
:
switch
{
case
x
.
c
<
2
*
kd
:
t
.
insert
(
x
,
i
,
k
,
v
)
default
:
t
.
overflow
(
p
,
x
,
pi
,
i
,
k
,
v
)
}
t
.
ver
++
return
}
}
}
z
:=
t
.
insert
(
&
d
{},
0
,
k
,
v
)
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
)
{
r
:=
&
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
if
pi
>=
0
{
p
.
insert
(
pi
,
r
,
r
)
}
else
{
t
.
r
=
newX
(
q
)
.
insert
(
0
,
r
,
r
)
}
if
i
>
kd
{
t
.
insert
(
r
,
i
-
kd
,
k
,
v
)
return
}
t
.
insert
(
q
,
i
,
k
,
v
)
}
func
(
t
*
Tree
)
splitX
(
p
*
x
,
pp
**
x
,
pi
int
,
i
*
int
)
{
q
:=
*
pp
r
:=
&
x
{}
copy
(
r
.
x
[
:
],
q
.
x
[
kx
+
1
:
])
q
.
c
=
kx
r
.
c
=
kx
if
pi
>=
0
{
p
.
insert
(
pi
,
q
.
x
[
kx
]
.
sep
,
r
)
}
else
{
t
.
r
=
newX
(
q
)
.
insert
(
0
,
q
.
x
[
kx
]
.
sep
,
r
)
}
q
.
x
[
kx
]
.
sep
=
nil
for
i
:=
range
q
.
x
[
kx
+
1
:
]
{
q
.
x
[
kx
+
i
+
1
]
=
zxe
}
if
*
i
>
kx
{
*
pp
=
r
*
i
-=
kx
+
1
}
}
func
(
t
*
Tree
)
underflow
(
p
*
x
,
q
*
d
,
pi
int
)
{
l
,
r
:=
p
.
siblings
(
pi
)
if
l
!=
nil
&&
l
.
c
+
q
.
c
>=
2
*
kd
{
l
.
mvR
(
q
,
1
)
}
else
if
r
!=
nil
&&
q
.
c
+
r
.
c
>=
2
*
kd
{
q
.
mvL
(
r
,
1
)
r
.
d
[
r
.
c
]
=
zde
// GC
}
else
if
l
!=
nil
{
t
.
cat
(
p
,
l
,
q
,
pi
-
1
)
}
else
{
t
.
cat
(
p
,
q
,
r
,
pi
)
}
}
func
(
t
*
Tree
)
underflowX
(
p
*
x
,
pp
**
x
,
pi
int
,
i
*
int
)
{
var
l
,
r
*
x
q
:=
*
pp
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
]
.
sep
=
p
.
x
[
pi
-
1
]
.
sep
q
.
c
++
*
i
++
l
.
c
--
p
.
x
[
pi
-
1
]
.
sep
=
l
.
x
[
l
.
c
]
.
sep
return
}
if
r
!=
nil
&&
r
.
c
>
kx
{
q
.
x
[
q
.
c
]
.
sep
=
p
.
x
[
pi
]
.
sep
q
.
c
++
q
.
x
[
q
.
c
]
.
ch
=
r
.
x
[
0
]
.
ch
p
.
x
[
pi
]
.
sep
=
r
.
x
[
0
]
.
sep
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
]
.
sep
=
nil
r
.
x
[
rc
+
1
]
.
ch
=
nil
return
}
if
l
!=
nil
{
*
i
+=
l
.
c
+
1
t
.
catX
(
p
,
l
,
q
,
pi
-
1
)
*
pp
=
l
return
}
t
.
catX
(
p
,
q
,
r
,
pi
)
}
// ----------------------------------------------------------------- Enumerator
// 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
}
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
}
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
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment