-
Notifications
You must be signed in to change notification settings - Fork 1
/
btree.go
229 lines (207 loc) · 6 KB
/
btree.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package btree
import "sync"
const (
Less = -1
Equal = 0
Greater = 1
)
// CompareAgainst is a comparison function that compares a reference item to
// an item in the Tree.
// An example of how it should work:
//
// comparer := func(reference i) CompareAgainst {
// return func(treeItem i) int {
// switch {
// case LessThan(treeItem, reference): return Less
// case LessThan(reference, treeItem): return Greater
// default: return Equal
// }
// }
// }
//
// CompareAgainst must return:
//
// * Less if the item in the tree is less than the reference
//
// * Equal if the item in the tree is equal to the reference
//
// * Greater if the item in the tree is greater than the reference
type CompareAgainst[T any] func(T) int
// LessThan compares two values to see if the first is LessThan than
// the second. The Tree code considers any values where neither is LessThan the other
// to be equal.
type LessThan[T any] func(T, T) bool
// Tree is an AVL tree.
type Tree[T any] struct {
root *node[T]
less LessThan[T]
nodePool *sync.Pool
insertCount, insertRebalanceCount uint64
removeCount, removeRebalanceCount uint64
count int
}
// New allocates a new Tree that will keep itself ordered according to the passed in LessThan.
func New[T any](lt LessThan[T]) *Tree[T] {
res := &Tree[T]{}
res.less = lt
res.nodePool = &sync.Pool{New: func() any { return &node[T]{} }}
return res
}
// Cmp takes a reference T and makes a valid CompareAgainst
// using the tree's current LessThan comparator.
func (t *Tree[T]) Cmp(reference T) CompareAgainst[T] {
less := t.less
return func(treeVal T) int {
if less(treeVal, reference) {
return Less
}
if less(reference, treeVal) {
return Greater
}
return Equal
}
}
// Release caches the memory that the Tree refers to for later reuse.
// You must not reuse any part of the Tree after calling Release.
func (t *Tree[T]) Release() {
t.count = 0
t.less = nil
if t.root != nil {
t.releaseNodes(t.root)
t.root = nil
}
}
// Reverse reverses a Tree in-place by swizzling the pointers in the nodes
// around and inverting the ordering function. This avoids needing to
// make a copy of the tree and resort the data. If you want to do that,
// make a Clone of the Tree and Reverse that.
func (t *Tree[T]) Reverse() {
ll := t.less
t.less = func(a, b T) bool { return ll(b, a) }
if t.root == nil {
return
}
var n *node[T]
i := t.Iterator(nil, nil)
for i.Next() {
if n != nil {
n.r, n.l = n.l, n.r
}
n = i.workingNode
}
n.r, n.l = n.l, n.r
}
// Copy makes a new copy of the Tree that has the same ordering function
// but no data. Trees created using Copy (or any functions that use it)
// use the same sync.Pool of nodes.
func (t *Tree[T]) Copy() *Tree[T] {
res := New[T](t.less)
res.nodePool = t.nodePool
return res
}
// Clone makes a full copy of the Tree, including all data.
func (t *Tree[T]) Clone() *Tree[T] {
res := t.Copy()
res.root = t.copyNodes(t.root, res)
return res
}
// SortBy returns a new empty Tree with an ordering function that falls back to
// t.less if the passed-in LessThan considers two items to be equal.
// This (and SortedClone) can be used to implement trees that will maintain items in
// arbitrarily complicated sort orders.
func (t *Tree[T]) SortBy(l LessThan[T]) *Tree[T] {
prevLess := t.less
res := New[T](func(a, b T) bool {
switch {
case l(a, b):
return true
case l(b, a):
return false
default:
return prevLess(a, b)
}
})
res.nodePool = t.nodePool
return res
}
// SortedClone makes a new Tree using SortBy, then inserts all the data from t into it.
func (t *Tree[T]) SortedClone(l LessThan[T]) *Tree[T] {
res := t.SortBy(l)
iter := t.Iterator(nil, nil)
for iter.Next() {
res.Insert(iter.Item())
}
return res
}
// Len returns the number of nodes in the tree.
func (t *Tree[T]) Len() int { return t.count }
const unorderable = `Unorderable CompareAgainst passed to Get`
// Get returns either the highest item in the tree that is equal to CompareAgainst and true,
// or a zero T and false if there is no such value in the Tree.
// The Tree must be sorted at the top level in the order that CompareAgainst expects, or you
// will get nonsense results. If you want to retrieve all
// the items matching CompareAgainst, use one of the Range, Before, or After instead.
func (t *Tree[T]) Get(cmp CompareAgainst[T]) (item T, found bool) {
h := t.root
for h != nil {
switch cmp(h.i) {
case Greater:
h = h.l
case Less:
h = h.r
case Equal:
item, found = h.i, true
return
default:
panic(unorderable)
}
}
return
}
// Has returns true if the tree contains an element equal to CompareAgainst.
func (t *Tree[T]) Has(cmp CompareAgainst[T]) bool {
_, found := t.Get(cmp)
return found
}
// Fetch returns the exact match for item, true if it is in the tree,
// or the zero value for T, false if it is not.
func (t *Tree[T]) Fetch(item T) (v T, found bool) {
if n, dir := t.getExact(t.root, item); dir == Equal {
v, found = n.i, true
}
return
}
// Min returns the smallest item in the Tree and true, or a zero T and false if the tree is empty.
func (t *Tree[T]) Min() (item T, found bool) {
if t.root != nil {
found = true
item = min(t.root).i
}
return
}
// Max returns the largest item in the Tree and true, or a zero T and false if the tree is empty.
func (t *Tree[T]) Max() (item T, found bool) {
if t.root != nil {
found = true
item = max(t.root).i
}
return
}
// Insert an item into the tree. If there is an existing value in the Tree that
// is equal to item, item will replace that value.
func (t *Tree[T]) Insert(item T) {
if t.root == nil {
t.root = t.newNode(item)
} else {
t.insert(item)
}
}
// Delete item from the tree, returning the item deleted
// or an empty i if the item was not in the tree.
func (t *Tree[T]) Delete(item T) (deleted T, found bool) {
if t.root == nil {
return
}
deleted, found = t.remove(item)
return
}