diff --git a/vendor/github.com/google/btree/.travis.yml b/vendor/github.com/tidwall/btree/.travis.yml similarity index 100% rename from vendor/github.com/google/btree/.travis.yml rename to vendor/github.com/tidwall/btree/.travis.yml diff --git a/vendor/github.com/google/btree/LICENSE b/vendor/github.com/tidwall/btree/LICENSE similarity index 100% rename from vendor/github.com/google/btree/LICENSE rename to vendor/github.com/tidwall/btree/LICENSE diff --git a/vendor/github.com/google/btree/README.md b/vendor/github.com/tidwall/btree/README.md similarity index 97% rename from vendor/github.com/google/btree/README.md rename to vendor/github.com/tidwall/btree/README.md index 26d687ef..6062a4da 100644 --- a/vendor/github.com/google/btree/README.md +++ b/vendor/github.com/tidwall/btree/README.md @@ -2,7 +2,7 @@ ![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. The API is based off of the wonderful diff --git a/vendor/github.com/google/btree/btree.go b/vendor/github.com/tidwall/btree/btree.go similarity index 76% rename from vendor/github.com/google/btree/btree.go rename to vendor/github.com/tidwall/btree/btree.go index fc5aaaa1..bcd0d1c5 100644 --- a/vendor/github.com/google/btree/btree.go +++ b/vendor/github.com/tidwall/btree/btree.go @@ -44,7 +44,7 @@ // widely used ordered tree implementation in the Go ecosystem currently. // Its functions, therefore, exactly mirror those of // llrb.LLRB where possible. Unlike gollrb, though, we currently don't -// support storing multiple equivalent values or backwards iteration. +// support storing multiple equivalent values. package btree import ( @@ -61,7 +61,10 @@ type Item interface { // This must provide a strict weak ordering. // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only // hold one of either a or b in the tree). - Less(than Item) bool + // + // There is a user-defined ctx argument that is equal to the ctx value which + // is set at time of the btree contruction. + Less(than Item, ctx int) bool } const ( @@ -106,18 +109,20 @@ type ItemIterator func(i Item) bool // // New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items // and 2-4 children). -func New(degree int) *BTree { - return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize)) +// The ctx param is user-defined. +func New(degree, ctx int) *BTree { + return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize), ctx) } // NewWithFreeList creates a new B-Tree that uses the given node free list. -func NewWithFreeList(degree int, f *FreeList) *BTree { +func NewWithFreeList(degree int, f *FreeList, ctx int) *BTree { if degree <= 1 { panic("bad degree") } return &BTree{ degree: degree, freelist: f, + ctx: ctx, } } @@ -156,11 +161,11 @@ func (s *items) pop() (out Item) { // find returns the index where the given item should be inserted into this // list. 'found' is true if the item already exists in the list at the given // index. -func (s items) find(item Item) (index int, found bool) { +func (s items) find(item Item, ctx int) (index int, found bool) { i := sort.Search(len(s), func(i int) bool { - return item.Less(s[i]) + return item.Less(s[i], ctx) }) - if i > 0 && !s[i-1].Less(item) { + if i > 0 && !s[i-1].Less(item, ctx) { return i - 1, true } return i, false @@ -240,8 +245,8 @@ func (n *node) maybeSplitChild(i, maxItems int) bool { // insert inserts an item into the subtree rooted at this node, making sure // no nodes in the subtree exceed maxItems items. Should an equivalent item be // be found/replaced by insert, it will be returned. -func (n *node) insert(item Item, maxItems int) Item { - i, found := n.items.find(item) +func (n *node) insert(item Item, maxItems int, ctx int) Item { + i, found := n.items.find(item, ctx) if found { out := n.items[i] n.items[i] = item @@ -254,9 +259,9 @@ func (n *node) insert(item Item, maxItems int) Item { if n.maybeSplitChild(i, maxItems) { inTree := n.items[i] switch { - case item.Less(inTree): + case item.Less(inTree, ctx): // no change, we want first split node - case inTree.Less(item): + case inTree.Less(item, ctx): i++ // we want second split node default: out := n.items[i] @@ -264,16 +269,16 @@ func (n *node) insert(item Item, maxItems int) Item { return out } } - return n.children[i].insert(item, maxItems) + return n.children[i].insert(item, maxItems, ctx) } // get finds the given key in the subtree and returns it. -func (n *node) get(key Item) Item { - i, found := n.items.find(key) +func (n *node) get(key Item, ctx int) Item { + i, found := n.items.find(key, ctx) if found { return n.items[i] } else if len(n.children) > 0 { - return n.children[i].get(key) + return n.children[i].get(key, ctx) } return nil } @@ -316,7 +321,7 @@ const ( ) // remove removes an item from the subtree rooted at this node. -func (n *node) remove(item Item, minItems int, typ toRemove) Item { +func (n *node) remove(item Item, minItems int, typ toRemove, ctx int) Item { var i int var found bool switch typ { @@ -331,7 +336,7 @@ func (n *node) remove(item Item, minItems int, typ toRemove) Item { } i = 0 case removeItem: - i, found = n.items.find(item) + i, found = n.items.find(item, ctx) if len(n.children) == 0 { if found { return n.items.removeAt(i) @@ -344,7 +349,7 @@ func (n *node) remove(item Item, minItems int, typ toRemove) Item { // If we get to here, we have children. child := n.children[i] if len(child.items) <= minItems { - return n.growChildAndRemove(i, item, minItems, typ) + return n.growChildAndRemove(i, item, minItems, typ, ctx) } // Either we had enough items to begin with, or we've done some // merging/stealing, because we've got enough now and we're ready to return @@ -356,12 +361,12 @@ func (n *node) remove(item Item, minItems int, typ toRemove) Item { // We use our special-case 'remove' call with typ=maxItem to pull the // predecessor of item i (the rightmost leaf of our immediate left child) // and set it into where we pulled the item from. - n.items[i] = child.remove(nil, minItems, removeMax) + n.items[i] = child.remove(nil, minItems, removeMax, ctx) return out } // Final recursive call. Once we're here, we know that the item isn't in this // node and that the child is big enough to remove from. - return child.remove(item, minItems, typ) + return child.remove(item, minItems, typ, ctx) } // growChildAndRemove grows child 'i' to make sure it's possible to remove an @@ -383,7 +388,7 @@ func (n *node) remove(item Item, minItems int, typ toRemove) Item { // We then simply redo our remove call, and the second time (regardless of // whether we're in case 1 or 2), we'll have enough items and can guarantee // that we hit case A. -func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) Item { +func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove, ctx int) Item { child := n.children[i] if i > 0 && len(n.children[i-1].items) > minItems { // Steal from left child @@ -416,37 +421,80 @@ func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) child.children = append(child.children, mergeChild.children...) n.t.freeNode(mergeChild) } - return n.remove(item, minItems, typ) + return n.remove(item, minItems, typ, ctx) } +type direction int + +const ( + descend = direction(-1) + ascend = direction(+1) +) + // iterate provides a simple method for iterating over elements in the tree. -// It could probably use some work to be extra-efficient (it calls from() a -// little more than it should), but it works pretty well for now. // -// It requires that 'from' and 'to' both return true for values we should hit -// with the iterator. It should also be the case that 'from' returns true for -// values less than or equal to values 'to' returns true for, and 'to' -// returns true for values greater than or equal to those that 'from' -// does. -func (n *node) iterate(from, to func(Item) bool, iter ItemIterator) bool { - for i, item := range n.items { - if !from(item) { - continue +// When ascending, the 'start' should be less than 'stop' and when descending, +// the 'start' should be greater than 'stop'. Setting 'includeStart' to true +// will force the iterator to include the first item when it equals 'start', +// thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a +// "greaterThan" or "lessThan" queries. +func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit bool, iter ItemIterator, ctx int) (bool, bool) { + var ok bool + switch dir { + case ascend: + for i := 0; i < len(n.items); i++ { + if start != nil && n.items[i].Less(start, ctx) { + continue + } + if len(n.children) > 0 { + if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter, ctx); !ok { + return hit, false + } + } + if !includeStart && !hit && start != nil && !start.Less(n.items[i], ctx) { + hit = true + continue + } + hit = true + if stop != nil && !n.items[i].Less(stop, ctx) { + return hit, false + } + if !iter(n.items[i]) { + return hit, false + } } - if len(n.children) > 0 && !n.children[i].iterate(from, to, iter) { - return false + if len(n.children) > 0 { + if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter, ctx); !ok { + return hit, false + } } - if !to(item) { - return false + case descend: + for i := len(n.items) - 1; i >= 0; i-- { + if start != nil && !n.items[i].Less(start, ctx) { + if !includeStart || hit || start.Less(n.items[i], ctx) { + continue + } + } + if len(n.children) > 0 { + if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter, ctx); !ok { + return hit, false + } + } + if stop != nil && !stop.Less(n.items[i], ctx) { + return hit, false // continue + } + hit = true + if !iter(n.items[i]) { + return hit, false + } } - if !iter(item) { - return false + if len(n.children) > 0 { + if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter, ctx); !ok { + return hit, false + } } } - if len(n.children) > 0 { - return n.children[len(n.children)-1].iterate(from, to, iter) - } - return true + return hit, true } // Used for testing/debugging purposes. @@ -469,6 +517,7 @@ type BTree struct { length int root *node freelist *FreeList + ctx int } // maxItems returns the max number of items to allow per node. @@ -522,7 +571,7 @@ func (t *BTree) ReplaceOrInsert(item Item) Item { t.root.items = append(t.root.items, item2) t.root.children = append(t.root.children, oldroot, second) } - out := t.root.insert(item, t.maxItems()) + out := t.root.insert(item, t.maxItems(), t.ctx) if out == nil { t.length++ } @@ -532,26 +581,26 @@ func (t *BTree) ReplaceOrInsert(item Item) Item { // Delete removes an item equal to the passed in item from the tree, returning // it. If no such item exists, returns nil. func (t *BTree) Delete(item Item) Item { - return t.deleteItem(item, removeItem) + return t.deleteItem(item, removeItem, t.ctx) } // DeleteMin removes the smallest item in the tree and returns it. // If no such item exists, returns nil. func (t *BTree) DeleteMin() Item { - return t.deleteItem(nil, removeMin) + return t.deleteItem(nil, removeMin, t.ctx) } // DeleteMax removes the largest item in the tree and returns it. // If no such item exists, returns nil. func (t *BTree) DeleteMax() Item { - return t.deleteItem(nil, removeMax) + return t.deleteItem(nil, removeMax, t.ctx) } -func (t *BTree) deleteItem(item Item, typ toRemove) Item { +func (t *BTree) deleteItem(item Item, typ toRemove, ctx int) Item { if t.root == nil || len(t.root.items) == 0 { return nil } - out := t.root.remove(item, t.minItems(), typ) + out := t.root.remove(item, t.minItems(), typ, ctx) if len(t.root.items) == 0 && len(t.root.children) > 0 { oldroot := t.root t.root = t.root.children[0] @@ -569,10 +618,7 @@ func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator if t.root == nil { return } - t.root.iterate( - func(a Item) bool { return !a.Less(greaterOrEqual) }, - func(a Item) bool { return a.Less(lessThan) }, - iterator) + t.root.iterate(ascend, greaterOrEqual, lessThan, true, false, iterator, t.ctx) } // AscendLessThan calls the iterator for every value in the tree within the range @@ -581,10 +627,7 @@ func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) { if t.root == nil { return } - t.root.iterate( - func(a Item) bool { return true }, - func(a Item) bool { return a.Less(pivot) }, - iterator) + t.root.iterate(ascend, nil, pivot, false, false, iterator, t.ctx) } // AscendGreaterOrEqual calls the iterator for every value in the tree within @@ -593,10 +636,7 @@ func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { if t.root == nil { return } - t.root.iterate( - func(a Item) bool { return !a.Less(pivot) }, - func(a Item) bool { return true }, - iterator) + t.root.iterate(ascend, pivot, nil, true, false, iterator, t.ctx) } // Ascend calls the iterator for every value in the tree within the range @@ -605,10 +645,43 @@ func (t *BTree) Ascend(iterator ItemIterator) { if t.root == nil { return } - t.root.iterate( - func(a Item) bool { return true }, - func(a Item) bool { return true }, - iterator) + t.root.iterate(ascend, nil, nil, false, false, iterator, t.ctx) +} + +// DescendRange calls the iterator for every value in the tree within the range +// [lessOrEqual, greaterThan), until iterator returns false. +func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, lessOrEqual, greaterThan, true, false, iterator, t.ctx) +} + +// DescendLessOrEqual calls the iterator for every value in the tree within the range +// [pivot, first], until iterator returns false. +func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, pivot, nil, true, false, iterator, t.ctx) +} + +// DescendGreaterThan calls the iterator for every value in the tree within +// the range [last, pivot), until iterator returns false. +func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, nil, pivot, false, false, iterator, t.ctx) +} + +// Descend calls the iterator for every value in the tree within the range +// [last, first], until iterator returns false. +func (t *BTree) Descend(iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, nil, nil, false, false, iterator, t.ctx) } // Get looks for the key item in the tree, returning it. It returns nil if @@ -617,7 +690,7 @@ func (t *BTree) Get(key Item) Item { if t.root == nil { return nil } - return t.root.get(key) + return t.root.get(key, t.ctx) } // Min returns the smallest item in the tree, or nil if the tree is empty. @@ -644,6 +717,6 @@ func (t *BTree) Len() int { type Int int // Less returns true if int(a) < int(b). -func (a Int) Less(b Item) bool { +func (a Int) Less(b Item, ctx int) bool { return a < b.(Int) } diff --git a/vendor/github.com/google/btree/btree_mem.go b/vendor/github.com/tidwall/btree/btree_mem.go similarity index 100% rename from vendor/github.com/google/btree/btree_mem.go rename to vendor/github.com/tidwall/btree/btree_mem.go diff --git a/vendor/github.com/google/btree/btree_test.go b/vendor/github.com/tidwall/btree/btree_test.go similarity index 71% rename from vendor/github.com/google/btree/btree_test.go rename to vendor/github.com/tidwall/btree/btree_test.go index 0a2fdde1..092839dd 100644 --- a/vendor/github.com/google/btree/btree_test.go +++ b/vendor/github.com/tidwall/btree/btree_test.go @@ -54,10 +54,27 @@ func all(t *BTree) (out []Item) { return } +// rangerev returns a reversed ordered list of Int items in the range [0, n). +func rangrev(n int) (out []Item) { + for i := n - 1; i >= 0; i-- { + out = append(out, Int(i)) + } + return +} + +// allrev extracts all items from a tree in reverse order as a slice. +func allrev(t *BTree) (out []Item) { + t.Descend(func(a Item) bool { + out = append(out, a) + return true + }) + return +} + var btreeDegree = flag.Int("degree", 32, "B-Tree degree") func TestBTree(t *testing.T) { - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) const treeSize = 10000 for i := 0; i < 10; i++ { if min := tr.Min(); min != nil { @@ -87,6 +104,13 @@ func TestBTree(t *testing.T) { if !reflect.DeepEqual(got, want) { t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) } + + gotrev := allrev(tr) + wantrev := rangrev(treeSize) + if !reflect.DeepEqual(gotrev, wantrev) { + t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) + } + for _, item := range perm(treeSize) { if x := tr.Delete(item); x == nil { t.Fatalf("didn't find %v", item) @@ -99,7 +123,7 @@ func TestBTree(t *testing.T) { } func ExampleBTree() { - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) for i := Int(0); i < 10; i++ { tr.ReplaceOrInsert(i) } @@ -131,7 +155,7 @@ func ExampleBTree() { } func TestDeleteMin(t *testing.T) { - tr := New(3) + tr := New(3, 0) for _, v := range perm(100) { tr.ReplaceOrInsert(v) } @@ -145,7 +169,7 @@ func TestDeleteMin(t *testing.T) { } func TestDeleteMax(t *testing.T) { - tr := New(3) + tr := New(3, 0) for _, v := range perm(100) { tr.ReplaceOrInsert(v) } @@ -163,7 +187,7 @@ func TestDeleteMax(t *testing.T) { } func TestAscendRange(t *testing.T) { - tr := New(2) + tr := New(2, 0) for _, v := range perm(100) { tr.ReplaceOrInsert(v) } @@ -188,8 +212,33 @@ func TestAscendRange(t *testing.T) { } } +func TestDescendRange(t *testing.T) { + tr := New(2, 0) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.DescendRange(Int(60), Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rangrev(100)[39:59]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.DescendRange(Int(60), Int(40), func(a Item) bool { + if a.(Int) < 50 { + return false + } + got = append(got, a) + return true + }) + if want := rangrev(100)[39:50]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want) + } +} func TestAscendLessThan(t *testing.T) { - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) for _, v := range perm(100) { tr.ReplaceOrInsert(v) } @@ -214,8 +263,33 @@ func TestAscendLessThan(t *testing.T) { } } +func TestDescendLessOrEqual(t *testing.T) { + tr := New(*btreeDegree, 0) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.DescendLessOrEqual(Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rangrev(100)[59:]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.DescendLessOrEqual(Int(60), func(a Item) bool { + if a.(Int) < 50 { + return false + } + got = append(got, a) + return true + }) + if want := rangrev(100)[39:50]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want) + } +} func TestAscendGreaterOrEqual(t *testing.T) { - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) for _, v := range perm(100) { tr.ReplaceOrInsert(v) } @@ -240,6 +314,32 @@ func TestAscendGreaterOrEqual(t *testing.T) { } } +func TestDescendGreaterThan(t *testing.T) { + tr := New(*btreeDegree, 0) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.DescendGreaterThan(Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rangrev(100)[:59]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.DescendGreaterThan(Int(40), func(a Item) bool { + if a.(Int) < 50 { + return false + } + got = append(got, a) + return true + }) + if want := rangrev(100)[:50]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want) + } +} + const benchmarkTreeSize = 10000 func BenchmarkInsert(b *testing.B) { @@ -248,7 +348,7 @@ func BenchmarkInsert(b *testing.B) { b.StartTimer() i := 0 for i < b.N { - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) for _, item := range insertP { tr.ReplaceOrInsert(item) i++ @@ -267,7 +367,7 @@ func BenchmarkDelete(b *testing.B) { i := 0 for i < b.N { b.StopTimer() - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) for _, v := range insertP { tr.ReplaceOrInsert(v) } @@ -293,7 +393,7 @@ func BenchmarkGet(b *testing.B) { i := 0 for i < b.N { b.StopTimer() - tr := New(*btreeDegree) + tr := New(*btreeDegree, 0) for _, v := range insertP { tr.ReplaceOrInsert(v) }