Browse Source
started by copying from https://sourcegraph.com/github.com/timtadh/data-structures@master/-/tree/tree/bptree
pull/2354/head
started by copying from https://sourcegraph.com/github.com/timtadh/data-structures@master/-/tree/tree/bptree
pull/2354/head
Chris Lu
3 years ago
8 changed files with 2982 additions and 0 deletions
-
77weed/util/bptree/bpmap.go
-
160weed/util/bptree/bptree.go
-
752weed/util/bptree/bptree_node.go
-
1460weed/util/bptree/bptree_test.go
-
357weed/util/bptree/int.go
-
2weed/util/bptree/rand.go
-
71weed/util/bptree/string.go
-
103weed/util/bptree/types.go
@ -0,0 +1,77 @@ |
|||||
|
package bptree |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
/* A BpMap is a B+Tree with support for duplicate keys disabled. This makes it |
||||
|
* behave like a regular Map rather than a MultiMap. |
||||
|
*/ |
||||
|
type BpMap BpTree |
||||
|
|
||||
|
func NewBpMap(node_size int) *BpMap { |
||||
|
return &BpMap{ |
||||
|
root: NewLeaf(node_size, true), |
||||
|
size: 0, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Size() int { |
||||
|
return (*BpTree)(self).Size() |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Has(key Hashable) bool { |
||||
|
return (*BpTree)(self).Has(key) |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Put(key Hashable, value interface{}) (err error) { |
||||
|
had := self.Has(key) |
||||
|
new_root, err := self.root.put(key, value) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
self.root = new_root |
||||
|
if !had { |
||||
|
self.size += 1 |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Get(key Hashable) (value interface{}, err error) { |
||||
|
j, l := self.root.get_start(key) |
||||
|
if l.keys[j].Equals(key) { |
||||
|
return l.values[j], nil |
||||
|
} |
||||
|
return nil, fmt.Errorf("key not found: %s", key) |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Remove(key Hashable) (value interface{}, err error) { |
||||
|
value, err = self.Get(key) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
ns := self.root.NodeSize() |
||||
|
new_root, err := self.root.remove(key, func(value interface{}) bool { return true }) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if new_root == nil { |
||||
|
self.root = NewLeaf(ns, true) |
||||
|
} else { |
||||
|
self.root = new_root |
||||
|
} |
||||
|
self.size-- |
||||
|
return value, nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Keys() (ki KIterator) { |
||||
|
return (*BpTree)(self).Keys() |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Values() (vi Iterator) { |
||||
|
return (*BpTree)(self).Values() |
||||
|
} |
||||
|
|
||||
|
func (self *BpMap) Iterate() (kvi KVIterator) { |
||||
|
return (*BpTree)(self).Iterate() |
||||
|
} |
@ -0,0 +1,160 @@ |
|||||
|
package bptree |
||||
|
|
||||
|
// started by copying from https://sourcegraph.com/github.com/timtadh/data-structures@master/-/tree/tree/bptree
|
||||
|
|
||||
|
/* A BpTree is a B+Tree with support for duplicate keys. This makes it behave as |
||||
|
* a MultiMap. Additionally you can use the Range operator to select k/v in a |
||||
|
* range. If from > to it will iterate backwards. |
||||
|
*/ |
||||
|
type BpTree struct { |
||||
|
root *BpNode |
||||
|
size int |
||||
|
} |
||||
|
|
||||
|
type loc_iterator func() (i int, leaf *BpNode, li loc_iterator) |
||||
|
|
||||
|
func NewBpTree(node_size int) *BpTree { |
||||
|
return &BpTree{ |
||||
|
root: NewLeaf(node_size, false), |
||||
|
size: 0, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Size() int { |
||||
|
return self.size |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Has(key Hashable) bool { |
||||
|
if len(self.root.keys) == 0 { |
||||
|
return false |
||||
|
} |
||||
|
j, l := self.root.get_start(key) |
||||
|
return l.keys[j].Equals(key) |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Count(key Hashable) int { |
||||
|
if len(self.root.keys) == 0 { |
||||
|
return 0 |
||||
|
} |
||||
|
j, l := self.root.get_start(key) |
||||
|
count := 0 |
||||
|
end := false |
||||
|
for !end && l.keys[j].Equals(key) { |
||||
|
count++ |
||||
|
j, l, end = next_location(j, l) |
||||
|
} |
||||
|
return count |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Add(key Hashable, value interface{}) (err error) { |
||||
|
new_root, err := self.root.put(key, value) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
self.root = new_root |
||||
|
self.size += 1 |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Replace(key Hashable, where WhereFunc, value interface{}) (err error) { |
||||
|
li := self.root.forward(key, key) |
||||
|
for i, leaf, next := li(); next != nil; i, leaf, next = next() { |
||||
|
if where(leaf.values[i]) { |
||||
|
leaf.values[i] = value |
||||
|
} |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Find(key Hashable) (kvi KVIterator) { |
||||
|
return self.Range(key, key) |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Range(from, to Hashable) (kvi KVIterator) { |
||||
|
var li loc_iterator |
||||
|
if !to.Less(from) { |
||||
|
li = self.root.forward(from, to) |
||||
|
} else { |
||||
|
li = self.root.backward(from, to) |
||||
|
} |
||||
|
kvi = func() (key Hashable, value interface{}, next KVIterator) { |
||||
|
var i int |
||||
|
var leaf *BpNode |
||||
|
i, leaf, li = li() |
||||
|
if li == nil { |
||||
|
return nil, nil, nil |
||||
|
} |
||||
|
return leaf.keys[i], leaf.values[i], kvi |
||||
|
} |
||||
|
return kvi |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) RemoveWhere(key Hashable, where WhereFunc) (err error) { |
||||
|
ns := self.root.NodeSize() |
||||
|
new_root, err := self.root.remove(key, where) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if new_root == nil { |
||||
|
self.root = NewLeaf(ns, false) |
||||
|
} else { |
||||
|
self.root = new_root |
||||
|
} |
||||
|
self.size -= 1 |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Keys() (ki KIterator) { |
||||
|
li := self.root.all() |
||||
|
var prev Equatable |
||||
|
ki = func() (key Hashable, next KIterator) { |
||||
|
var i int |
||||
|
var leaf *BpNode |
||||
|
i, leaf, li = li() |
||||
|
if li == nil { |
||||
|
return nil, nil |
||||
|
} |
||||
|
if leaf.keys[i].Equals(prev) { |
||||
|
return ki() |
||||
|
} |
||||
|
prev = leaf.keys[i] |
||||
|
return leaf.keys[i], ki |
||||
|
} |
||||
|
return ki |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Values() (vi Iterator) { |
||||
|
return MakeValuesIterator(self) |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Items() (vi KIterator) { |
||||
|
return MakeItemsIterator(self) |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Iterate() (kvi KVIterator) { |
||||
|
li := self.root.all() |
||||
|
kvi = func() (key Hashable, value interface{}, next KVIterator) { |
||||
|
var i int |
||||
|
var leaf *BpNode |
||||
|
i, leaf, li = li() |
||||
|
if li == nil { |
||||
|
return nil, nil, nil |
||||
|
} |
||||
|
return leaf.keys[i], leaf.values[i], kvi |
||||
|
} |
||||
|
return kvi |
||||
|
} |
||||
|
|
||||
|
func (self *BpTree) Backward() (kvi KVIterator) { |
||||
|
li := self.root.all_backward() |
||||
|
kvi = func() (key Hashable, value interface{}, next KVIterator) { |
||||
|
var i int |
||||
|
var leaf *BpNode |
||||
|
i, leaf, li = li() |
||||
|
if li == nil { |
||||
|
return nil, nil, nil |
||||
|
} |
||||
|
return leaf.keys[i], leaf.values[i], kvi |
||||
|
} |
||||
|
return kvi |
||||
|
} |
@ -0,0 +1,752 @@ |
|||||
|
package bptree |
||||
|
|
||||
|
type BpNode struct { |
||||
|
keys []Hashable |
||||
|
values []interface{} |
||||
|
pointers []*BpNode |
||||
|
next *BpNode |
||||
|
prev *BpNode |
||||
|
no_dup bool |
||||
|
} |
||||
|
|
||||
|
func NewInternal(size int) *BpNode { |
||||
|
if size < 0 { |
||||
|
panic(NegativeSize()) |
||||
|
} |
||||
|
return &BpNode{ |
||||
|
keys: make([]Hashable, 0, size), |
||||
|
pointers: make([]*BpNode, 0, size), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func NewLeaf(size int, no_dup bool) *BpNode { |
||||
|
if size < 0 { |
||||
|
panic(NegativeSize()) |
||||
|
} |
||||
|
return &BpNode{ |
||||
|
keys: make([]Hashable, 0, size), |
||||
|
values: make([]interface{}, 0, size), |
||||
|
no_dup: no_dup, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) Full() bool { |
||||
|
return len(self.keys) == cap(self.keys) |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) Pure() bool { |
||||
|
if len(self.keys) == 0 { |
||||
|
return true |
||||
|
} |
||||
|
k0 := self.keys[0] |
||||
|
for _, k := range self.keys { |
||||
|
if !k0.Equals(k) { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) Internal() bool { |
||||
|
return cap(self.pointers) > 0 |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) NodeSize() int { |
||||
|
return cap(self.keys) |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) Height() int { |
||||
|
if !self.Internal() { |
||||
|
return 1 |
||||
|
} else if len(self.pointers) == 0 { |
||||
|
panic(BpTreeError("Internal node has no pointers but asked for height")) |
||||
|
} |
||||
|
return self.pointers[0].Height() + 1 |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) count(key Hashable) int { |
||||
|
i, _ := self.find(key) |
||||
|
count := 0 |
||||
|
for ; i < len(self.keys); i++ { |
||||
|
if self.keys[i].Equals(key) { |
||||
|
count++ |
||||
|
} else { |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
return count |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) has(key Hashable) bool { |
||||
|
_, has := self.find(key) |
||||
|
return has |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) left_most_leaf() *BpNode { |
||||
|
if self.Internal() { |
||||
|
return self.pointers[0].left_most_leaf() |
||||
|
} |
||||
|
return self |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) right_most_leaf() *BpNode { |
||||
|
if self.Internal() { |
||||
|
return self.pointers[len(self.pointers)-1].right_most_leaf() |
||||
|
} |
||||
|
return self |
||||
|
} |
||||
|
|
||||
|
/* returns the index and leaf-block of the first key greater than or equal to |
||||
|
* the search key. (unless the search key is greater than all the keys in the |
||||
|
* tree, in that case it will be the last key in the tree) |
||||
|
*/ |
||||
|
func (self *BpNode) get_start(key Hashable) (i int, leaf *BpNode) { |
||||
|
if self.Internal() { |
||||
|
return self.internal_get_start(key) |
||||
|
} else { |
||||
|
return self.leaf_get_start(key) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func next_location(i int, leaf *BpNode) (int, *BpNode, bool) { |
||||
|
j := i + 1 |
||||
|
for j >= len(leaf.keys) && leaf.next != nil { |
||||
|
j = 0 |
||||
|
leaf = leaf.next |
||||
|
} |
||||
|
if j >= len(leaf.keys) { |
||||
|
return -1, nil, true |
||||
|
} |
||||
|
return j, leaf, false |
||||
|
} |
||||
|
|
||||
|
func prev_location(i int, leaf *BpNode) (int, *BpNode, bool) { |
||||
|
j := i - 1 |
||||
|
for j < 0 && leaf.prev != nil { |
||||
|
leaf = leaf.prev |
||||
|
j = len(leaf.keys) - 1 |
||||
|
} |
||||
|
if j < 0 { |
||||
|
return -1, nil, true |
||||
|
} |
||||
|
return j, leaf, false |
||||
|
} |
||||
|
|
||||
|
/* returns the index and leaf-block of the last key equal to the search key or |
||||
|
* the first key greater than the search key. (unless the search key is greater |
||||
|
* than all the keys in the tree, in that case it will be the last key in the |
||||
|
* tree) |
||||
|
*/ |
||||
|
func (self *BpNode) get_end(key Hashable) (i int, leaf *BpNode) { |
||||
|
end := false |
||||
|
i, leaf = self.get_start(key) |
||||
|
pi, pleaf := i, leaf |
||||
|
for !end && leaf.keys[i].Equals(key) { |
||||
|
pi, pleaf = i, leaf |
||||
|
i, leaf, end = next_location(i, leaf) |
||||
|
} |
||||
|
return pi, pleaf |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) internal_get_start(key Hashable) (i int, leaf *BpNode) { |
||||
|
if !self.Internal() { |
||||
|
panic(BpTreeError("Expected a internal node")) |
||||
|
} |
||||
|
i, has := self.find(key) |
||||
|
if !has && i > 0 { |
||||
|
// if it doesn't have it and the index > 0 then we have the next block
|
||||
|
// so we have to subtract one from the index.
|
||||
|
i-- |
||||
|
} |
||||
|
child := self.pointers[i] |
||||
|
return child.get_start(key) |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) leaf_get_start(key Hashable) (i int, leaf *BpNode) { |
||||
|
i, has := self.find(key) |
||||
|
if i >= len(self.keys) && i > 0 { |
||||
|
i = len(self.keys) - 1 |
||||
|
} |
||||
|
if !has && (len(self.keys) == 0 || self.keys[i].Less(key)) && self.next != nil { |
||||
|
return self.next.leaf_get_start(key) |
||||
|
} |
||||
|
return i, self |
||||
|
} |
||||
|
|
||||
|
/* This puts the k/v pair into the B+Tree rooted at this node and returns the |
||||
|
* (possibly) new root of the tree. |
||||
|
*/ |
||||
|
func (self *BpNode) put(key Hashable, value interface{}) (root *BpNode, err error) { |
||||
|
a, b, err := self.insert(key, value) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} else if b == nil { |
||||
|
return a, nil |
||||
|
} |
||||
|
// else we have root split
|
||||
|
root = NewInternal(self.NodeSize()) |
||||
|
root.put_kp(a.keys[0], a) |
||||
|
root.put_kp(b.keys[0], b) |
||||
|
return root, nil |
||||
|
} |
||||
|
|
||||
|
// right is only set on split
|
||||
|
// left is always set. When split is false left is the pointer to block
|
||||
|
// When split is true left is the pointer to the new left
|
||||
|
// block
|
||||
|
func (self *BpNode) insert(key Hashable, value interface{}) (a, b *BpNode, err error) { |
||||
|
if self.Internal() { |
||||
|
return self.internal_insert(key, value) |
||||
|
} else { // leaf node
|
||||
|
return self.leaf_insert(key, value) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* - first find the child to insert into |
||||
|
* - do the child insert |
||||
|
* - if there was a split: |
||||
|
* - if the block is full, split this block |
||||
|
* - else insert the new key/pointer into this block |
||||
|
*/ |
||||
|
func (self *BpNode) internal_insert(key Hashable, value interface{}) (a, b *BpNode, err error) { |
||||
|
if !self.Internal() { |
||||
|
return nil, nil, BpTreeError("Expected a internal node") |
||||
|
} |
||||
|
i, has := self.find(key) |
||||
|
if !has && i > 0 { |
||||
|
// if it doesn't have it and the index > 0 then we have the next block
|
||||
|
// so we have to subtract one from the index.
|
||||
|
i-- |
||||
|
} |
||||
|
child := self.pointers[i] |
||||
|
p, q, err := child.insert(key, value) |
||||
|
if err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
self.keys[i] = p.keys[0] |
||||
|
self.pointers[i] = p |
||||
|
if q != nil { |
||||
|
// we had a split
|
||||
|
if self.Full() { |
||||
|
return self.internal_split(q.keys[0], q) |
||||
|
} else { |
||||
|
if err := self.put_kp(q.keys[0], q); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
return self, nil, nil |
||||
|
} |
||||
|
} |
||||
|
return self, nil, nil |
||||
|
} |
||||
|
|
||||
|
/* On split |
||||
|
* - first assert that the key to be inserted is not already in the block. |
||||
|
* - Make a new block |
||||
|
* - balance the two blocks. |
||||
|
* - insert the new key/pointer combo into the correct block |
||||
|
*/ |
||||
|
func (self *BpNode) internal_split(key Hashable, ptr *BpNode) (a, b *BpNode, err error) { |
||||
|
if !self.Internal() { |
||||
|
return nil, nil, BpTreeError("Expected a internal node") |
||||
|
} |
||||
|
if self.has(key) { |
||||
|
return nil, nil, BpTreeError("Tried to split an internal block on duplicate key") |
||||
|
} |
||||
|
a = self |
||||
|
b = NewInternal(self.NodeSize()) |
||||
|
balance_nodes(a, b) |
||||
|
if key.Less(b.keys[0]) { |
||||
|
if err := a.put_kp(key, ptr); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
} else { |
||||
|
if err := b.put_kp(key, ptr); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
} |
||||
|
return a, b, nil |
||||
|
} |
||||
|
|
||||
|
/* if the leaf is full then it will defer to a leaf_split |
||||
|
* (but in one case that will not actually split in the case of a insert into |
||||
|
* a pure block with a matching key) |
||||
|
* else this leaf will get a new entry. |
||||
|
*/ |
||||
|
func (self *BpNode) leaf_insert(key Hashable, value interface{}) (a, b *BpNode, err error) { |
||||
|
if self.Internal() { |
||||
|
return nil, nil, BpTreeError("Expected a leaf node") |
||||
|
} |
||||
|
if self.no_dup { |
||||
|
i, has := self.find(key) |
||||
|
if has { |
||||
|
self.values[i] = value |
||||
|
return self, nil, nil |
||||
|
} |
||||
|
} |
||||
|
if self.Full() { |
||||
|
return self.leaf_split(key, value) |
||||
|
} else { |
||||
|
if err := self.put_kv(key, value); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
return self, nil, nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* on leaf split if the block is pure then it will defer to pure_leaf_split |
||||
|
* else |
||||
|
* - a new block will be made and inserted after this one |
||||
|
* - the two blocks will be balanced with balanced_nodes |
||||
|
* - if the key is less than b.keys[0] it will go in a else b |
||||
|
*/ |
||||
|
func (self *BpNode) leaf_split(key Hashable, value interface{}) (a, b *BpNode, err error) { |
||||
|
if self.Internal() { |
||||
|
return nil, nil, BpTreeError("Expected a leaf node") |
||||
|
} |
||||
|
if self.Pure() { |
||||
|
return self.pure_leaf_split(key, value) |
||||
|
} |
||||
|
a = self |
||||
|
b = NewLeaf(self.NodeSize(), self.no_dup) |
||||
|
insert_linked_list_node(b, a, a.next) |
||||
|
balance_nodes(a, b) |
||||
|
if key.Less(b.keys[0]) { |
||||
|
if err := a.put_kv(key, value); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
} else { |
||||
|
if err := b.put_kv(key, value); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
} |
||||
|
return a, b, nil |
||||
|
} |
||||
|
|
||||
|
/* a pure leaf split has two cases: |
||||
|
* 1) the inserted key is less than the current pure block. |
||||
|
* - a new block should be created before the current block |
||||
|
* - the key should be put in it |
||||
|
* 2) the inserted key is greater than or equal to the pure block. |
||||
|
* - the end of run of pure blocks should be found |
||||
|
* - if the key is equal to pure block and the last block is not full insert |
||||
|
* the new kv |
||||
|
* - else split by making a new block after the last block in the run |
||||
|
* and putting the new key there. |
||||
|
* - always return the current block as "a" and the new block as "b" |
||||
|
*/ |
||||
|
func (self *BpNode) pure_leaf_split(key Hashable, value interface{}) (a, b *BpNode, err error) { |
||||
|
if self.Internal() || !self.Pure() { |
||||
|
return nil, nil, BpTreeError("Expected a pure leaf node") |
||||
|
} |
||||
|
if key.Less(self.keys[0]) { |
||||
|
a = NewLeaf(self.NodeSize(), self.no_dup) |
||||
|
b = self |
||||
|
if err := a.put_kv(key, value); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
insert_linked_list_node(a, b.prev, b) |
||||
|
return a, b, nil |
||||
|
} else { |
||||
|
a = self |
||||
|
e := self.find_end_of_pure_run() |
||||
|
if e.keys[0].Equals(key) && !e.Full() { |
||||
|
if err := e.put_kv(key, value); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
return a, nil, nil |
||||
|
} else { |
||||
|
b = NewLeaf(self.NodeSize(), self.no_dup) |
||||
|
if err := b.put_kv(key, value); err != nil { |
||||
|
return nil, nil, err |
||||
|
} |
||||
|
insert_linked_list_node(b, e, e.next) |
||||
|
if e.keys[0].Equals(key) { |
||||
|
return a, nil, nil |
||||
|
} |
||||
|
return a, b, nil |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) put_kp(key Hashable, ptr *BpNode) error { |
||||
|
if self.Full() { |
||||
|
return BpTreeError("Block is full.") |
||||
|
} |
||||
|
if !self.Internal() { |
||||
|
return BpTreeError("Expected a internal node") |
||||
|
} |
||||
|
i, has := self.find(key) |
||||
|
if has { |
||||
|
return BpTreeError("Tried to insert a duplicate key into an internal node") |
||||
|
} else if i < 0 { |
||||
|
panic(BpTreeError("find returned a negative int")) |
||||
|
} else if i >= cap(self.keys) { |
||||
|
panic(BpTreeError("find returned a int > than cap(keys)")) |
||||
|
} |
||||
|
if err := self.put_key_at(i, key); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if err := self.put_pointer_at(i, ptr); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) put_kv(key Hashable, value interface{}) error { |
||||
|
if self.Full() { |
||||
|
return BpTreeError("Block is full.") |
||||
|
} |
||||
|
if self.Internal() { |
||||
|
return BpTreeError("Expected a leaf node") |
||||
|
} |
||||
|
i, _ := self.find(key) |
||||
|
if i < 0 { |
||||
|
panic(BpTreeError("find returned a negative int")) |
||||
|
} else if i >= cap(self.keys) { |
||||
|
panic(BpTreeError("find returned a int > than cap(keys)")) |
||||
|
} |
||||
|
if err := self.put_key_at(i, key); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if err := self.put_value_at(i, value); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) put_key_at(i int, key Hashable) error { |
||||
|
if self.Full() { |
||||
|
return BpTreeError("Block is full.") |
||||
|
} |
||||
|
self.keys = self.keys[:len(self.keys)+1] |
||||
|
for j := len(self.keys) - 1; j > i; j-- { |
||||
|
self.keys[j] = self.keys[j-1] |
||||
|
} |
||||
|
self.keys[i] = key |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) put_value_at(i int, value interface{}) error { |
||||
|
if len(self.values) == cap(self.values) { |
||||
|
return BpTreeError("Block is full.") |
||||
|
} |
||||
|
if self.Internal() { |
||||
|
return BpTreeError("Expected a leaf node") |
||||
|
} |
||||
|
self.values = self.values[:len(self.values)+1] |
||||
|
for j := len(self.values) - 1; j > i; j-- { |
||||
|
self.values[j] = self.values[j-1] |
||||
|
} |
||||
|
self.values[i] = value |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) put_pointer_at(i int, pointer *BpNode) error { |
||||
|
if len(self.pointers) == cap(self.pointers) { |
||||
|
return BpTreeError("Block is full.") |
||||
|
} |
||||
|
if !self.Internal() { |
||||
|
return BpTreeError("Expected a internal node") |
||||
|
} |
||||
|
self.pointers = self.pointers[:len(self.pointers)+1] |
||||
|
for j := len(self.pointers) - 1; j > i; j-- { |
||||
|
self.pointers[j] = self.pointers[j-1] |
||||
|
} |
||||
|
self.pointers[i] = pointer |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) remove(key Hashable, where WhereFunc) (a *BpNode, err error) { |
||||
|
if self.Internal() { |
||||
|
return self.internal_remove(key, nil, where) |
||||
|
} else { |
||||
|
return self.leaf_remove(key, self.keys[len(self.keys)-1], where) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) internal_remove(key Hashable, sibling *BpNode, where WhereFunc) (a *BpNode, err error) { |
||||
|
if !self.Internal() { |
||||
|
panic(BpTreeError("Expected a internal node")) |
||||
|
} |
||||
|
i, has := self.find(key) |
||||
|
if !has && i > 0 { |
||||
|
// if it doesn't have it and the index > 0 then we have the next block
|
||||
|
// so we have to subtract one from the index.
|
||||
|
i-- |
||||
|
} |
||||
|
if i+1 < len(self.keys) { |
||||
|
sibling = self.pointers[i+1] |
||||
|
} else if sibling != nil { |
||||
|
sibling = sibling.left_most_leaf() |
||||
|
} |
||||
|
child := self.pointers[i] |
||||
|
if child.Internal() { |
||||
|
child, err = child.internal_remove(key, sibling, where) |
||||
|
} else { |
||||
|
if sibling == nil { |
||||
|
child, err = child.leaf_remove(key, nil, where) |
||||
|
} else { |
||||
|
child, err = child.leaf_remove(key, sibling.keys[0], where) |
||||
|
} |
||||
|
} |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if child == nil { |
||||
|
if err := self.remove_key_at(i); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if err := self.remove_ptr_at(i); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
} else { |
||||
|
self.keys[i] = child.keys[0] |
||||
|
self.pointers[i] = child |
||||
|
} |
||||
|
if len(self.keys) == 0 { |
||||
|
return nil, nil |
||||
|
} |
||||
|
return self, nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) leaf_remove(key, stop Hashable, where WhereFunc) (a *BpNode, err error) { |
||||
|
if self.Internal() { |
||||
|
return nil, BpTreeError("Expected a leaf node") |
||||
|
} |
||||
|
a = self |
||||
|
for j, l, next := self.forward(key, key)(); next != nil; j, l, next = next() { |
||||
|
if where(l.values[j]) { |
||||
|
if err := l.remove_key_at(j); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if err := l.remove_value_at(j); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
} |
||||
|
if len(l.keys) == 0 { |
||||
|
remove_linked_list_node(l) |
||||
|
if l.next == nil { |
||||
|
a = nil |
||||
|
} else if stop == nil { |
||||
|
a = nil |
||||
|
} else if !l.next.keys[0].Equals(stop) { |
||||
|
a = l.next |
||||
|
} else { |
||||
|
a = nil |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return a, nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) remove_key_at(i int) error { |
||||
|
if i >= len(self.keys) || i < 0 { |
||||
|
return BpTreeError("i, %v, is out of bounds, %v, %v %v.", i, len(self.keys), len(self.values), self) |
||||
|
} |
||||
|
for j := i; j < len(self.keys)-1; j++ { |
||||
|
self.keys[j] = self.keys[j+1] |
||||
|
} |
||||
|
self.keys = self.keys[:len(self.keys)-1] |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) remove_value_at(i int) error { |
||||
|
if i >= len(self.values) || i < 0 { |
||||
|
return BpTreeError("i, %v, is out of bounds, %v.", i, len(self.values)) |
||||
|
} |
||||
|
for j := i; j < len(self.values)-1; j++ { |
||||
|
self.values[j] = self.values[j+1] |
||||
|
} |
||||
|
self.values = self.values[:len(self.values)-1] |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) remove_ptr_at(i int) error { |
||||
|
if i >= len(self.pointers) || i < 0 { |
||||
|
return BpTreeError("i, %v, is out of bounds, %v.", i, len(self.pointers)) |
||||
|
} |
||||
|
for j := i; j < len(self.pointers)-1; j++ { |
||||
|
self.pointers[j] = self.pointers[j+1] |
||||
|
} |
||||
|
self.pointers = self.pointers[:len(self.pointers)-1] |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) find(key Hashable) (int, bool) { |
||||
|
var l int = 0 |
||||
|
var r int = len(self.keys) - 1 |
||||
|
var m int |
||||
|
for l <= r { |
||||
|
m = ((r - l) >> 1) + l |
||||
|
if key.Less(self.keys[m]) { |
||||
|
r = m - 1 |
||||
|
} else if key.Equals(self.keys[m]) { |
||||
|
for j := m; j >= 0; j-- { |
||||
|
if j == 0 || !key.Equals(self.keys[j-1]) { |
||||
|
return j, true |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
l = m + 1 |
||||
|
} |
||||
|
} |
||||
|
return l, false |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) find_end_of_pure_run() *BpNode { |
||||
|
k := self.keys[0] |
||||
|
p := self |
||||
|
n := self.next |
||||
|
for n != nil && n.Pure() && k.Equals(n.keys[0]) { |
||||
|
p = n |
||||
|
n = n.next |
||||
|
} |
||||
|
return p |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) all() (li loc_iterator) { |
||||
|
j := -1 |
||||
|
l := self.left_most_leaf() |
||||
|
end := false |
||||
|
j, l, end = next_location(j, l) |
||||
|
li = func() (i int, leaf *BpNode, next loc_iterator) { |
||||
|
if end { |
||||
|
return -1, nil, nil |
||||
|
} |
||||
|
i = j |
||||
|
leaf = l |
||||
|
j, l, end = next_location(j, l) |
||||
|
return i, leaf, li |
||||
|
} |
||||
|
return li |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) all_backward() (li loc_iterator) { |
||||
|
l := self.right_most_leaf() |
||||
|
j := len(l.keys) |
||||
|
end := false |
||||
|
j, l, end = prev_location(j, l) |
||||
|
li = func() (i int, leaf *BpNode, next loc_iterator) { |
||||
|
if end { |
||||
|
return -1, nil, nil |
||||
|
} |
||||
|
i = j |
||||
|
leaf = l |
||||
|
j, l, end = prev_location(j, l) |
||||
|
return i, leaf, li |
||||
|
} |
||||
|
return li |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) forward(from, to Hashable) (li loc_iterator) { |
||||
|
j, l := self.get_start(from) |
||||
|
end := false |
||||
|
j-- |
||||
|
li = func() (i int, leaf *BpNode, next loc_iterator) { |
||||
|
j, l, end = next_location(j, l) |
||||
|
if end || to.Less(l.keys[j]) { |
||||
|
return -1, nil, nil |
||||
|
} |
||||
|
return j, l, li |
||||
|
} |
||||
|
return li |
||||
|
} |
||||
|
|
||||
|
func (self *BpNode) backward(from, to Hashable) (li loc_iterator) { |
||||
|
j, l := self.get_end(from) |
||||
|
end := false |
||||
|
li = func() (i int, leaf *BpNode, next loc_iterator) { |
||||
|
if end || l.keys[j].Less(to) { |
||||
|
return -1, nil, nil |
||||
|
} |
||||
|
i = j |
||||
|
leaf = l |
||||
|
j, l, end = prev_location(i, l) |
||||
|
return i, leaf, li |
||||
|
} |
||||
|
return li |
||||
|
} |
||||
|
|
||||
|
func insert_linked_list_node(n, prev, next *BpNode) { |
||||
|
if (prev != nil && prev.next != next) || (next != nil && next.prev != prev) { |
||||
|
panic(BpTreeError("prev and next not hooked up")) |
||||
|
} |
||||
|
n.prev = prev |
||||
|
n.next = next |
||||
|
if prev != nil { |
||||
|
prev.next = n |
||||
|
} |
||||
|
if next != nil { |
||||
|
next.prev = n |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func remove_linked_list_node(n *BpNode) { |
||||
|
if n.prev != nil { |
||||
|
n.prev.next = n.next |
||||
|
} |
||||
|
if n.next != nil { |
||||
|
n.next.prev = n.prev |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* a must be full and b must be empty else there will be a panic |
||||
|
*/ |
||||
|
func balance_nodes(a, b *BpNode) { |
||||
|
if len(b.keys) != 0 { |
||||
|
panic(BpTreeError("b was not empty")) |
||||
|
} |
||||
|
if !a.Full() { |
||||
|
panic(BpTreeError("a was not full", a)) |
||||
|
} |
||||
|
if cap(a.keys) != cap(b.keys) { |
||||
|
panic(BpTreeError("cap(a.keys) != cap(b.keys)")) |
||||
|
} |
||||
|
if cap(a.values) != cap(b.values) { |
||||
|
panic(BpTreeError("cap(a.values) != cap(b.values)")) |
||||
|
} |
||||
|
if cap(a.pointers) != cap(b.pointers) { |
||||
|
panic(BpTreeError("cap(a.pointers) != cap(b.pointers)")) |
||||
|
} |
||||
|
m := len(a.keys) / 2 |
||||
|
for m < len(a.keys) && a.keys[m-1].Equals(a.keys[m]) { |
||||
|
m++ |
||||
|
} |
||||
|
if m == len(a.keys) { |
||||
|
m-- |
||||
|
for m > 0 && a.keys[m-1].Equals(a.keys[m]) { |
||||
|
m-- |
||||
|
} |
||||
|
} |
||||
|
var lim int = len(a.keys) - m |
||||
|
b.keys = b.keys[:lim] |
||||
|
if cap(a.values) > 0 { |
||||
|
if cap(a.values) != cap(a.keys) { |
||||
|
panic(BpTreeError("cap(a.values) != cap(a.keys)")) |
||||
|
} |
||||
|
b.values = b.values[:lim] |
||||
|
} |
||||
|
if cap(a.pointers) > 0 { |
||||
|
if cap(a.pointers) != cap(a.keys) { |
||||
|
panic(BpTreeError("cap(a.pointers) != cap(a.keys)")) |
||||
|
} |
||||
|
b.pointers = b.pointers[:lim] |
||||
|
} |
||||
|
for i := 0; i < lim; i++ { |
||||
|
j := m + i |
||||
|
b.keys[i] = a.keys[j] |
||||
|
if cap(a.values) > 0 { |
||||
|
b.values[i] = a.values[j] |
||||
|
} |
||||
|
if cap(a.pointers) > 0 { |
||||
|
b.pointers[i] = a.pointers[j] |
||||
|
} |
||||
|
} |
||||
|
a.keys = a.keys[:m] |
||||
|
if cap(a.values) > 0 { |
||||
|
a.values = a.values[:m] |
||||
|
} |
||||
|
if cap(a.pointers) > 0 { |
||||
|
a.pointers = a.pointers[:m] |
||||
|
} |
||||
|
} |
1460
weed/util/bptree/bptree_test.go
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,357 @@ |
|||||
|
package bptree |
||||
|
|
||||
|
import ( |
||||
|
"encoding/binary" |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
type Int8 int8 |
||||
|
type UInt8 uint8 |
||||
|
type Int16 int16 |
||||
|
type UInt16 uint16 |
||||
|
type Int32 int32 |
||||
|
type UInt32 uint32 |
||||
|
type Int64 int64 |
||||
|
type UInt64 uint64 |
||||
|
type Int int |
||||
|
type UInt uint |
||||
|
|
||||
|
func (self *Int8) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 0) |
||||
|
bytes[0] = uint8(*self) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *Int8) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 1 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = Int8(data[0]) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self Int8) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(Int8); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int8) Less(other Sortable) bool { |
||||
|
if o, ok := other.(Int8); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int8) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *UInt8) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 0) |
||||
|
bytes[0] = uint8(*self) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *UInt8) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 1 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = UInt8(data[0]) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self UInt8) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(UInt8); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt8) Less(other Sortable) bool { |
||||
|
if o, ok := other.(UInt8); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt8) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *Int16) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 2) |
||||
|
binary.BigEndian.PutUint16(bytes, uint16(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *Int16) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 2 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = Int16(binary.BigEndian.Uint16(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self Int16) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(Int16); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int16) Less(other Sortable) bool { |
||||
|
if o, ok := other.(Int16); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int16) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *UInt16) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 2) |
||||
|
binary.BigEndian.PutUint16(bytes, uint16(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *UInt16) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 2 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = UInt16(binary.BigEndian.Uint16(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self UInt16) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(UInt16); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt16) Less(other Sortable) bool { |
||||
|
if o, ok := other.(UInt16); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt16) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *Int32) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 4) |
||||
|
binary.BigEndian.PutUint32(bytes, uint32(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *Int32) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 4 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = Int32(binary.BigEndian.Uint32(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self Int32) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(Int32); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int32) Less(other Sortable) bool { |
||||
|
if o, ok := other.(Int32); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self *UInt32) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 4) |
||||
|
binary.BigEndian.PutUint32(bytes, uint32(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *UInt32) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 4 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = UInt32(binary.BigEndian.Uint32(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self Int32) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self UInt32) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(UInt32); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt32) Less(other Sortable) bool { |
||||
|
if o, ok := other.(UInt32); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt32) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *Int64) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 8) |
||||
|
binary.BigEndian.PutUint64(bytes, uint64(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *Int64) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 8 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = Int64(binary.BigEndian.Uint64(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self Int64) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(Int64); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int64) Less(other Sortable) bool { |
||||
|
if o, ok := other.(Int64); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int64) Hash() int { |
||||
|
return int(self>>32) ^ int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *UInt64) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 8) |
||||
|
binary.BigEndian.PutUint64(bytes, uint64(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *UInt64) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 8 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = UInt64(binary.BigEndian.Uint64(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self UInt64) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(UInt64); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt64) Less(other Sortable) bool { |
||||
|
if o, ok := other.(UInt64); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt64) Hash() int { |
||||
|
return int(self>>32) ^ int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *Int) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 4) |
||||
|
binary.BigEndian.PutUint32(bytes, uint32(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *Int) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 4 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = Int(binary.BigEndian.Uint32(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self Int) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(Int); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int) Less(other Sortable) bool { |
||||
|
if o, ok := other.(Int); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self Int) Hash() int { |
||||
|
return int(self) |
||||
|
} |
||||
|
|
||||
|
func (self *UInt) MarshalBinary() ([]byte, error) { |
||||
|
bytes := make([]byte, 4) |
||||
|
binary.BigEndian.PutUint32(bytes, uint32(*self)) |
||||
|
return bytes, nil |
||||
|
} |
||||
|
|
||||
|
func (self *UInt) UnmarshalBinary(data []byte) error { |
||||
|
if len(data) != 4 { |
||||
|
return fmt.Errorf("data wrong size") |
||||
|
} |
||||
|
*self = UInt(binary.BigEndian.Uint32(data)) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self UInt) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(UInt); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt) Less(other Sortable) bool { |
||||
|
if o, ok := other.(UInt); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self UInt) Hash() int { |
||||
|
return int(self) |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
package bptree |
||||
|
|
@ -0,0 +1,71 @@ |
|||||
|
package bptree |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"hash/fnv" |
||||
|
) |
||||
|
|
||||
|
type String string |
||||
|
type ByteSlice []byte |
||||
|
|
||||
|
func (self *String) MarshalBinary() ([]byte, error) { |
||||
|
return []byte(*self), nil |
||||
|
} |
||||
|
|
||||
|
func (self *String) UnmarshalBinary(data []byte) error { |
||||
|
*self = String(data) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self String) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(String); ok { |
||||
|
return self == o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self String) Less(other Sortable) bool { |
||||
|
if o, ok := other.(String); ok { |
||||
|
return self < o |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self String) Hash() int { |
||||
|
h := fnv.New32a() |
||||
|
h.Write([]byte(string(self))) |
||||
|
return int(h.Sum32()) |
||||
|
} |
||||
|
|
||||
|
func (self *ByteSlice) MarshalBinary() ([]byte, error) { |
||||
|
return []byte(*self), nil |
||||
|
} |
||||
|
|
||||
|
func (self *ByteSlice) UnmarshalBinary(data []byte) error { |
||||
|
*self = ByteSlice(data) |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (self ByteSlice) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(ByteSlice); ok { |
||||
|
return bytes.Equal(self, o) |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self ByteSlice) Less(other Sortable) bool { |
||||
|
if o, ok := other.(ByteSlice); ok { |
||||
|
return bytes.Compare(self, o) < 0 // -1 if a < b
|
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (self ByteSlice) Hash() int { |
||||
|
h := fnv.New32a() |
||||
|
h.Write([]byte(self)) |
||||
|
return int(h.Sum32()) |
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
package bptree |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
type Equatable interface { |
||||
|
Equals(b Equatable) bool |
||||
|
} |
||||
|
|
||||
|
type Sortable interface { |
||||
|
Equatable |
||||
|
Less(b Sortable) bool |
||||
|
} |
||||
|
|
||||
|
type Hashable interface { |
||||
|
Sortable |
||||
|
Hash() int |
||||
|
} |
||||
|
|
||||
|
var BpTreeError = fmt.Errorf |
||||
|
|
||||
|
func NegativeSize() error { |
||||
|
return errors.New("negative size") |
||||
|
} |
||||
|
|
||||
|
type Iterator func() (item interface{}, next Iterator) |
||||
|
type KIterator func() (key Hashable, next KIterator) |
||||
|
type KVIterator func() (key Hashable, value interface{}, next KVIterator) |
||||
|
type KVIterable interface { |
||||
|
Iterate() KVIterator |
||||
|
} |
||||
|
|
||||
|
type Sized interface { |
||||
|
Size() int |
||||
|
} |
||||
|
|
||||
|
type MapOperable interface { |
||||
|
Sized |
||||
|
Has(key Hashable) bool |
||||
|
Put(key Hashable, value interface{}) (err error) |
||||
|
Get(key Hashable) (value interface{}, err error) |
||||
|
Remove(key Hashable) (value interface{}, err error) |
||||
|
} |
||||
|
|
||||
|
type WhereFunc func(value interface{}) bool |
||||
|
|
||||
|
func MakeValuesIterator(obj KVIterable) Iterator { |
||||
|
kv_iterator := obj.Iterate() |
||||
|
var v_iterator Iterator |
||||
|
v_iterator = func() (value interface{}, next Iterator) { |
||||
|
_, value, kv_iterator = kv_iterator() |
||||
|
if kv_iterator == nil { |
||||
|
return nil, nil |
||||
|
} |
||||
|
return value, v_iterator |
||||
|
} |
||||
|
return v_iterator |
||||
|
} |
||||
|
|
||||
|
func MakeItemsIterator(obj KVIterable) (kit KIterator) { |
||||
|
kv_iterator := obj.Iterate() |
||||
|
kit = func() (item Hashable, next KIterator) { |
||||
|
var key Hashable |
||||
|
var value interface{} |
||||
|
key, value, kv_iterator = kv_iterator() |
||||
|
if kv_iterator == nil { |
||||
|
return nil, nil |
||||
|
} |
||||
|
return &MapEntry{key, value}, kit |
||||
|
} |
||||
|
return kit |
||||
|
} |
||||
|
|
||||
|
type MapEntry struct { |
||||
|
Key Hashable |
||||
|
Value interface{} |
||||
|
} |
||||
|
|
||||
|
func (m *MapEntry) Equals(other Equatable) bool { |
||||
|
if o, ok := other.(*MapEntry); ok { |
||||
|
return m.Key.Equals(o.Key) |
||||
|
} else { |
||||
|
return m.Key.Equals(other) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (m *MapEntry) Less(other Sortable) bool { |
||||
|
if o, ok := other.(*MapEntry); ok { |
||||
|
return m.Key.Less(o.Key) |
||||
|
} else { |
||||
|
return m.Key.Less(other) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (m *MapEntry) Hash() int { |
||||
|
return m.Key.Hash() |
||||
|
} |
||||
|
|
||||
|
func (m *MapEntry) String() string { |
||||
|
return fmt.Sprintf("<MapEntry %v: %v>", m.Key, m.Value) |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue