*: update google/btree dependency

This commit is contained in:
Gyu-Ho Lee
2016-06-08 11:23:49 -07:00
parent ff2b24a8ac
commit 0b7e5c70a5
3 changed files with 99 additions and 21 deletions

View File

@ -88,7 +88,7 @@
}, },
{ {
"ImportPath": "github.com/google/btree", "ImportPath": "github.com/google/btree",
"Rev": "cc6329d4279e3f025a53a83c397d2339b5705c45" "Rev": "7d79101e329e5a3adf994758c578dab82b90c017"
}, },
{ {
"ImportPath": "github.com/inconshreveable/mousetrap", "ImportPath": "github.com/inconshreveable/mousetrap",

View File

@ -2,7 +2,7 @@
![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master) ![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master)
This package provides an in-memory B-Tree implementation for Go, useful as a This package provides an in-memory B-Tree implementation for Go, useful as
an ordered, mutable data structure. an ordered, mutable data structure.
The API is based off of the wonderful The API is based off of the wonderful

View File

@ -64,6 +64,39 @@ type Item interface {
Less(than Item) bool Less(than Item) bool
} }
const (
DefaultFreeListSize = 32
)
// FreeList represents a free list of btree nodes. By default each
// BTree has its own FreeList, but multiple BTrees can share the same
// FreeList.
// Two Btrees using the same freelist are not safe for concurrent write access.
type FreeList struct {
freelist []*node
}
// NewFreeList creates a new free list.
// size is the maximum size of the returned free list.
func NewFreeList(size int) *FreeList {
return &FreeList{freelist: make([]*node, 0, size)}
}
func (f *FreeList) newNode() (n *node) {
index := len(f.freelist) - 1
if index < 0 {
return new(node)
}
f.freelist, n = f.freelist[:index], f.freelist[index]
return
}
func (f *FreeList) freeNode(n *node) {
if len(f.freelist) < cap(f.freelist) {
f.freelist = append(f.freelist, n)
}
}
// ItemIterator allows callers of Ascend* to iterate in-order over portions of // ItemIterator allows callers of Ascend* to iterate in-order over portions of
// the tree. When this function returns false, iteration will stop and the // the tree. When this function returns false, iteration will stop and the
// associated Ascend* function will immediately return. // associated Ascend* function will immediately return.
@ -74,12 +107,17 @@ type ItemIterator func(i Item) bool
// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items // New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
// and 2-4 children). // and 2-4 children).
func New(degree int) *BTree { func New(degree int) *BTree {
return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize))
}
// NewWithFreeList creates a new B-Tree that uses the given node free list.
func NewWithFreeList(degree int, f *FreeList) *BTree {
if degree <= 1 { if degree <= 1 {
panic("bad degree") panic("bad degree")
} }
return &BTree{ return &BTree{
degree: degree, degree: degree,
freelist: make([]*node, 0, 32), freelist: f,
} }
} }
@ -100,6 +138,7 @@ func (s *items) insertAt(index int, item Item) {
// back. // back.
func (s *items) removeAt(index int) Item { func (s *items) removeAt(index int) Item {
item := (*s)[index] item := (*s)[index]
(*s)[index] = nil
copy((*s)[index:], (*s)[index+1:]) copy((*s)[index:], (*s)[index+1:])
*s = (*s)[:len(*s)-1] *s = (*s)[:len(*s)-1]
return item return item
@ -108,7 +147,9 @@ func (s *items) removeAt(index int) Item {
// pop removes and returns the last element in the list. // pop removes and returns the last element in the list.
func (s *items) pop() (out Item) { func (s *items) pop() (out Item) {
index := len(*s) - 1 index := len(*s) - 1
out, *s = (*s)[index], (*s)[:index] out = (*s)[index]
(*s)[index] = nil
*s = (*s)[:index]
return return
} }
@ -142,6 +183,7 @@ func (s *children) insertAt(index int, n *node) {
// back. // back.
func (s *children) removeAt(index int) *node { func (s *children) removeAt(index int) *node {
n := (*s)[index] n := (*s)[index]
(*s)[index] = nil
copy((*s)[index:], (*s)[index+1:]) copy((*s)[index:], (*s)[index+1:])
*s = (*s)[:len(*s)-1] *s = (*s)[:len(*s)-1]
return n return n
@ -150,7 +192,9 @@ func (s *children) removeAt(index int) *node {
// pop removes and returns the last element in the list. // pop removes and returns the last element in the list.
func (s *children) pop() (out *node) { func (s *children) pop() (out *node) {
index := len(*s) - 1 index := len(*s) - 1
out, *s = (*s)[index], (*s)[:index] out = (*s)[index]
(*s)[index] = nil
*s = (*s)[:index]
return return
} }
@ -234,6 +278,34 @@ func (n *node) get(key Item) Item {
return nil return nil
} }
// min returns the first item in the subtree.
func min(n *node) Item {
if n == nil {
return nil
}
for len(n.children) > 0 {
n = n.children[0]
}
if len(n.items) == 0 {
return nil
}
return n.items[0]
}
// max returns the last item in the subtree.
func max(n *node) Item {
if n == nil {
return nil
}
for len(n.children) > 0 {
n = n.children[len(n.children)-1]
}
if len(n.items) == 0 {
return nil
}
return n.items[len(n.items)-1]
}
// toRemove details what item to remove in a node.remove call. // toRemove details what item to remove in a node.remove call.
type toRemove int type toRemove int
@ -396,7 +468,7 @@ type BTree struct {
degree int degree int
length int length int
root *node root *node
freelist []*node freelist *FreeList
} }
// maxItems returns the max number of items to allow per node. // maxItems returns the max number of items to allow per node.
@ -411,26 +483,22 @@ func (t *BTree) minItems() int {
} }
func (t *BTree) newNode() (n *node) { func (t *BTree) newNode() (n *node) {
index := len(t.freelist) - 1 n = t.freelist.newNode()
if index < 0 { n.t = t
return &node{t: t}
}
t.freelist, n = t.freelist[:index], t.freelist[index]
return return
} }
func (t *BTree) freeNode(n *node) { func (t *BTree) freeNode(n *node) {
if len(t.freelist) < cap(t.freelist) { for i := range n.items {
for i := range n.items { n.items[i] = nil // clear to allow GC
n.items[i] = nil // clear to allow GC
}
n.items = n.items[:0]
for i := range n.children {
n.children[i] = nil // clear to allow GC
}
n.children = n.children[:0]
t.freelist = append(t.freelist, n)
} }
n.items = n.items[:0]
for i := range n.children {
n.children[i] = nil // clear to allow GC
}
n.children = n.children[:0]
n.t = nil // clear to allow GC
t.freelist.freeNode(n)
} }
// ReplaceOrInsert adds the given item to the tree. If an item in the tree // ReplaceOrInsert adds the given item to the tree. If an item in the tree
@ -552,6 +620,16 @@ func (t *BTree) Get(key Item) Item {
return t.root.get(key) return t.root.get(key)
} }
// Min returns the smallest item in the tree, or nil if the tree is empty.
func (t *BTree) Min() Item {
return min(t.root)
}
// Max returns the largest item in the tree, or nil if the tree is empty.
func (t *BTree) Max() Item {
return max(t.root)
}
// Has returns true if the given key is in the tree. // Has returns true if the given key is in the tree.
func (t *BTree) Has(key Item) bool { func (t *BTree) Has(key Item) bool {
return t.Get(key) != nil return t.Get(key) != nil