|
@@ -1,178 +1,109 @@
|
1
|
1
|
// Copyright 2020 Joshua J Baker. All rights reserved.
|
2
|
|
-// Use of this source code is governed by an MIT-style license that can be
|
3
|
|
-// found in the LICENSE file at https://github.com/tidwall/btree/LICENSE
|
4
|
|
-
|
5
|
|
-///////////////////////////////////////////////////////////////////////////////
|
6
|
|
-// BEGIN PARAMS
|
7
|
|
-///////////////////////////////////////////////////////////////////////////////
|
8
|
|
-
|
|
2
|
+// Use of this source code is governed by an MIT-style
|
|
3
|
+// license that can be found in the LICENSE file.
|
9
|
4
|
package btree
|
10
|
5
|
|
11
|
|
-import "sync"
|
12
|
|
-
|
13
|
|
-// degree is the B-Tree degree, which is equal to maximum number of children
|
14
|
|
-// pre node times two.
|
15
|
|
-// The default is 128, which means each node can have 255 items and 256 child
|
16
|
|
-// nodes.
|
17
|
|
-const degree = 128
|
18
|
|
-
|
19
|
|
-// kind is the item type.
|
20
|
|
-// It's important to use the equal symbol, which tells Go to create an alias of
|
21
|
|
-// the type, rather than creating an entirely new type.
|
22
|
|
-type kind = interface{}
|
23
|
|
-
|
24
|
|
-// contextKind is the kind of context that can be passed to NewOptions and the
|
25
|
|
-// less function
|
26
|
|
-type contextKind = interface{}
|
27
|
|
-
|
28
|
|
-// less returns true if A is less than B.
|
29
|
|
-// The value of context will be whatever was passed to NewOptions through the
|
30
|
|
-// Options.Context field, otherwise nil if the field was not set.
|
31
|
|
-func less(a, b kind, context contextKind) bool {
|
32
|
|
- return context.(func(a, b contextKind) bool)(a, b)
|
33
|
|
-}
|
34
|
|
-
|
35
|
|
-// BTree aliases
|
36
|
|
-// These are aliases to the local bTree types and functions, which are exported
|
37
|
|
-// to allow for public use at a package level.
|
38
|
|
-// Rename them if desired, or comment them out to make the library private.
|
39
|
|
-type BTree = bTree
|
40
|
|
-type Options = bOptions
|
41
|
|
-type PathHint = bPathHint
|
42
|
|
-type Iter = bIter
|
43
|
|
-
|
44
|
|
-func New(less func(a, b kind) bool) *bTree { return bNew() }
|
45
|
|
-func NewOptions(opts bOptions) *bTree { return bNewOptions(opts) }
|
46
|
|
-
|
47
|
|
-// The functions below, which begin with "test*", are required by the
|
48
|
|
-// btree_test.go file. If you choose not use include the btree_test.go file in
|
49
|
|
-// your project then these functions may be omitted.
|
50
|
|
-
|
51
|
|
-// testCustomSeed can be used to generate a custom random seed for testing.
|
52
|
|
-// Returning false will use time.Now().UnixNano()
|
53
|
|
-func testCustomSeed() (seed int64, ok bool) {
|
54
|
|
- return 0, false
|
55
|
|
-}
|
56
|
|
-
|
57
|
|
-// testMakeItem must return a valid item for testing.
|
58
|
|
-// It's required that the returned item maintains equal order as the
|
59
|
|
-// provided int, such that:
|
60
|
|
-// testMakeItem(0) < testMakeItem(1) < testMakeItem(2) < testMakeItem(10)
|
61
|
|
-func testMakeItem(x int) (item kind) {
|
62
|
|
- return x
|
63
|
|
-}
|
64
|
|
-
|
65
|
|
-// testNewBTree must return an operational btree for testing.
|
66
|
|
-func testNewBTree() *bTree {
|
67
|
|
- return bNewOptions(bOptions{
|
68
|
|
- Context: func(a, b contextKind) bool {
|
69
|
|
- if a == nil {
|
70
|
|
- return b != nil
|
71
|
|
- } else if b == nil {
|
72
|
|
- return false
|
73
|
|
- }
|
74
|
|
- return a.(int) < b.(int)
|
75
|
|
- },
|
76
|
|
- })
|
77
|
|
-}
|
78
|
|
-
|
79
|
|
-///////////////////////////////////////////////////////////////////////////////
|
80
|
|
-// END PARAMS
|
81
|
|
-///////////////////////////////////////////////////////////////////////////////
|
|
6
|
+import (
|
|
7
|
+ "sync"
|
|
8
|
+ "sync/atomic"
|
|
9
|
+)
|
82
|
10
|
|
83
|
|
-// Do not edit code below this line.
|
|
11
|
+const (
|
|
12
|
+ degree = 128
|
|
13
|
+ maxItems = degree*2 - 1 // max items per node. max children is +1
|
|
14
|
+ minItems = maxItems / 2
|
|
15
|
+)
|
84
|
16
|
|
85
|
|
-const maxItems = degree*2 - 1 // max items per node. max children is +1
|
86
|
|
-const minItems = maxItems / 2
|
87
|
|
-
|
88
|
|
-type bTree struct {
|
|
17
|
+type BTreeG[T any] struct {
|
89
|
18
|
mu *sync.RWMutex
|
90
|
|
- cow *cow
|
91
|
|
- root *node
|
|
19
|
+ cow uint64
|
|
20
|
+ root *node[T]
|
92
|
21
|
count int
|
93
|
|
- ctx contextKind
|
94
|
22
|
locks bool
|
95
|
|
- empty kind
|
|
23
|
+ less func(a, b T) bool
|
|
24
|
+ empty T
|
96
|
25
|
}
|
97
|
26
|
|
98
|
|
-type node struct {
|
99
|
|
- cow *cow
|
|
27
|
+type node[T any] struct {
|
|
28
|
+ cow uint64
|
100
|
29
|
count int
|
101
|
|
- items []kind
|
102
|
|
- children *[]*node
|
|
30
|
+ items []T
|
|
31
|
+ children *[]*node[T]
|
103
|
32
|
}
|
104
|
33
|
|
105
|
|
-type cow struct {
|
106
|
|
- _ int // cannot be an empty struct
|
107
|
|
-}
|
108
|
|
-
|
109
|
|
-func (tr *bTree) newNode(leaf bool) *node {
|
110
|
|
- n := &node{cow: tr.cow}
|
111
|
|
- if !leaf {
|
112
|
|
- n.children = new([]*node)
|
113
|
|
- }
|
114
|
|
- return n
|
115
|
|
-}
|
116
|
|
-
|
117
|
|
-// leaf returns true if the node is a leaf.
|
118
|
|
-func (n *node) leaf() bool {
|
119
|
|
- return n.children == nil
|
120
|
|
-}
|
|
34
|
+var gcow uint64
|
121
|
35
|
|
122
|
36
|
// PathHint is a utility type used with the *Hint() functions. Hints provide
|
123
|
37
|
// faster operations for clustered keys.
|
124
|
|
-type bPathHint struct {
|
|
38
|
+type PathHint struct {
|
125
|
39
|
used [8]bool
|
126
|
40
|
path [8]uint8
|
127
|
41
|
}
|
128
|
42
|
|
129
|
|
-type bOptions struct {
|
|
43
|
+// Options for passing to New when creating a new BTree.
|
|
44
|
+type Options struct {
|
130
|
45
|
NoLocks bool
|
131
|
|
- Context contextKind
|
132
|
46
|
}
|
133
|
47
|
|
134
|
48
|
// New returns a new BTree
|
135
|
|
-func bNew() *bTree {
|
136
|
|
- return bNewOptions(bOptions{})
|
|
49
|
+func NewBTreeG[T any](less func(a, b T) bool) *BTreeG[T] {
|
|
50
|
+ return NewBTreeGOptions(less, Options{})
|
137
|
51
|
}
|
138
|
52
|
|
139
|
|
-func bNewOptions(opts bOptions) *bTree {
|
140
|
|
- tr := new(bTree)
|
141
|
|
- tr.cow = new(cow)
|
|
53
|
+func NewBTreeGOptions[T any](less func(a, b T) bool, opts Options) *BTreeG[T] {
|
|
54
|
+ tr := new(BTreeG[T])
|
|
55
|
+ tr.cow = atomic.AddUint64(&gcow, 1)
|
142
|
56
|
tr.mu = new(sync.RWMutex)
|
143
|
|
- tr.ctx = opts.Context
|
|
57
|
+ tr.less = less
|
144
|
58
|
tr.locks = !opts.NoLocks
|
145
|
59
|
return tr
|
146
|
60
|
}
|
147
|
61
|
|
148
|
62
|
// Less is a convenience function that performs a comparison of two items
|
149
|
63
|
// using the same "less" function provided to New.
|
150
|
|
-func (tr *bTree) Less(a, b kind) bool {
|
151
|
|
- return less(a, b, tr.ctx)
|
|
64
|
+func (tr *BTreeG[T]) Less(a, b T) bool {
|
|
65
|
+ return tr.less(a, b)
|
|
66
|
+}
|
|
67
|
+
|
|
68
|
+func (tr *BTreeG[T]) newNode(leaf bool) *node[T] {
|
|
69
|
+ n := &node[T]{cow: tr.cow}
|
|
70
|
+ if !leaf {
|
|
71
|
+ n.children = new([]*node[T])
|
|
72
|
+ }
|
|
73
|
+ return n
|
|
74
|
+}
|
|
75
|
+
|
|
76
|
+// leaf returns true if the node is a leaf.
|
|
77
|
+func (n *node[T]) leaf() bool {
|
|
78
|
+ return n.children == nil
|
|
79
|
+}
|
|
80
|
+
|
|
81
|
+func (tr *BTreeG[T]) bsearch(n *node[T], key T) (index int, found bool) {
|
|
82
|
+ low, high := 0, len(n.items)
|
|
83
|
+ for low < high {
|
|
84
|
+ h := int(uint(low+high) >> 1)
|
|
85
|
+ if !tr.less(key, n.items[h]) {
|
|
86
|
+ low = h + 1
|
|
87
|
+ } else {
|
|
88
|
+ high = h
|
|
89
|
+ }
|
|
90
|
+ }
|
|
91
|
+ if low > 0 && !tr.less(n.items[low-1], key) {
|
|
92
|
+ return low - 1, true
|
|
93
|
+ }
|
|
94
|
+ return low, false
|
152
|
95
|
}
|
153
|
96
|
|
154
|
|
-func (tr *bTree) find(n *node, key kind,
|
155
|
|
- hint *bPathHint, depth int,
|
|
97
|
+func (tr *BTreeG[T]) find(n *node[T], key T, hint *PathHint, depth int,
|
156
|
98
|
) (index int, found bool) {
|
157
|
99
|
if hint == nil {
|
158
|
|
- // fast path for no hinting
|
159
|
|
- low := 0
|
160
|
|
- high := len(n.items)
|
161
|
|
- for low < high {
|
162
|
|
- mid := (low + high) / 2
|
163
|
|
- if !tr.Less(key, n.items[mid]) {
|
164
|
|
- low = mid + 1
|
165
|
|
- } else {
|
166
|
|
- high = mid
|
167
|
|
- }
|
168
|
|
- }
|
169
|
|
- if low > 0 && !tr.Less(n.items[low-1], key) {
|
170
|
|
- return low - 1, true
|
171
|
|
- }
|
172
|
|
- return low, false
|
|
100
|
+ return tr.bsearch(n, key)
|
173
|
101
|
}
|
|
102
|
+ return tr.hintsearch(n, key, hint, depth)
|
|
103
|
+}
|
174
|
104
|
|
175
|
|
- // Try using hint.
|
|
105
|
+func (tr *BTreeG[T]) hintsearch(n *node[T], key T, hint *PathHint, depth int,
|
|
106
|
+) (index int, found bool) {
|
176
|
107
|
// Best case finds the exact match, updates the hint and returns.
|
177
|
108
|
// Worst case, updates the low and high bounds to binary search between.
|
178
|
109
|
low := 0
|
|
@@ -247,17 +178,21 @@ path_match:
|
247
|
178
|
}
|
248
|
179
|
|
249
|
180
|
// SetHint sets or replace a value for a key using a path hint
|
250
|
|
-func (tr *bTree) SetHint(item kind, hint *bPathHint) (prev kind, replaced bool) {
|
251
|
|
- if tr.lock() {
|
252
|
|
- defer tr.unlock()
|
|
181
|
+func (tr *BTreeG[T]) SetHint(item T, hint *PathHint) (prev T, replaced bool) {
|
|
182
|
+ if tr.locks {
|
|
183
|
+ tr.mu.Lock()
|
|
184
|
+ prev, replaced = tr.setHint(item, hint)
|
|
185
|
+ tr.mu.Unlock()
|
|
186
|
+ } else {
|
|
187
|
+ prev, replaced = tr.setHint(item, hint)
|
253
|
188
|
}
|
254
|
|
- return tr.setHint(item, hint)
|
|
189
|
+ return prev, replaced
|
255
|
190
|
}
|
256
|
191
|
|
257
|
|
-func (tr *bTree) setHint(item kind, hint *bPathHint) (prev kind, replaced bool) {
|
|
192
|
+func (tr *BTreeG[T]) setHint(item T, hint *PathHint) (prev T, replaced bool) {
|
258
|
193
|
if tr.root == nil {
|
259
|
194
|
tr.root = tr.newNode(true)
|
260
|
|
- tr.root.items = append([]kind{}, item)
|
|
195
|
+ tr.root.items = append([]T{}, item)
|
261
|
196
|
tr.root.count = 1
|
262
|
197
|
tr.count = 1
|
263
|
198
|
return tr.empty, false
|
|
@@ -267,9 +202,9 @@ func (tr *bTree) setHint(item kind, hint *bPathHint) (prev kind, replaced bool)
|
267
|
202
|
left := tr.cowLoad(&tr.root)
|
268
|
203
|
right, median := tr.nodeSplit(left)
|
269
|
204
|
tr.root = tr.newNode(false)
|
270
|
|
- *tr.root.children = make([]*node, 0, maxItems+1)
|
271
|
|
- *tr.root.children = append([]*node{}, left, right)
|
272
|
|
- tr.root.items = append([]kind{}, median)
|
|
205
|
+ *tr.root.children = make([]*node[T], 0, maxItems+1)
|
|
206
|
+ *tr.root.children = append([]*node[T]{}, left, right)
|
|
207
|
+ tr.root.items = append([]T{}, median)
|
273
|
208
|
tr.root.updateCount()
|
274
|
209
|
return tr.setHint(item, hint)
|
275
|
210
|
}
|
|
@@ -281,39 +216,61 @@ func (tr *bTree) setHint(item kind, hint *bPathHint) (prev kind, replaced bool)
|
281
|
216
|
}
|
282
|
217
|
|
283
|
218
|
// Set or replace a value for a key
|
284
|
|
-func (tr *bTree) Set(item kind) (kind, bool) {
|
|
219
|
+func (tr *BTreeG[T]) Set(item T) (T, bool) {
|
285
|
220
|
return tr.SetHint(item, nil)
|
286
|
221
|
}
|
287
|
222
|
|
288
|
|
-func (tr *bTree) nodeSplit(n *node) (right *node, median kind) {
|
|
223
|
+func (tr *BTreeG[T]) nodeSplit(n *node[T]) (right *node[T], median T) {
|
289
|
224
|
i := maxItems / 2
|
290
|
225
|
median = n.items[i]
|
291
|
226
|
|
292
|
|
- // left node
|
293
|
|
- left := tr.newNode(n.leaf())
|
294
|
|
- left.items = make([]kind, len(n.items[:i]), maxItems/2)
|
295
|
|
- copy(left.items, n.items[:i])
|
296
|
|
- if !n.leaf() {
|
297
|
|
- *left.children = make([]*node, len((*n.children)[:i+1]), maxItems+1)
|
298
|
|
- copy(*left.children, (*n.children)[:i+1])
|
299
|
|
- }
|
300
|
|
- left.updateCount()
|
|
227
|
+ const sliceItems = true
|
301
|
228
|
|
302
|
229
|
// right node
|
303
|
230
|
right = tr.newNode(n.leaf())
|
304
|
|
- right.items = make([]kind, len(n.items[i+1:]), maxItems/2)
|
305
|
|
- copy(right.items, n.items[i+1:])
|
306
|
|
- if !n.leaf() {
|
307
|
|
- *right.children = make([]*node, len((*n.children)[i+1:]), maxItems+1)
|
308
|
|
- copy(*right.children, (*n.children)[i+1:])
|
|
231
|
+ if sliceItems {
|
|
232
|
+ right.items = n.items[i+1:]
|
|
233
|
+ if !n.leaf() {
|
|
234
|
+ *right.children = (*n.children)[i+1:]
|
|
235
|
+ }
|
|
236
|
+ } else {
|
|
237
|
+ right.items = make([]T, len(n.items[i+1:]), maxItems/2)
|
|
238
|
+ copy(right.items, n.items[i+1:])
|
|
239
|
+ if !n.leaf() {
|
|
240
|
+ *right.children =
|
|
241
|
+ make([]*node[T], len((*n.children)[i+1:]), maxItems+1)
|
|
242
|
+ copy(*right.children, (*n.children)[i+1:])
|
|
243
|
+ }
|
309
|
244
|
}
|
310
|
245
|
right.updateCount()
|
311
|
246
|
|
312
|
|
- *n = *left
|
|
247
|
+ // left node
|
|
248
|
+ if sliceItems {
|
|
249
|
+ n.items[i] = tr.empty
|
|
250
|
+ n.items = n.items[:i:i]
|
|
251
|
+ if !n.leaf() {
|
|
252
|
+ *n.children = (*n.children)[: i+1 : i+1]
|
|
253
|
+ }
|
|
254
|
+ } else {
|
|
255
|
+ for j := i; j < len(n.items); j++ {
|
|
256
|
+ n.items[j] = tr.empty
|
|
257
|
+ }
|
|
258
|
+ if !n.leaf() {
|
|
259
|
+ for j := i + 1; j < len((*n.children)); j++ {
|
|
260
|
+ (*n.children)[j] = nil
|
|
261
|
+ }
|
|
262
|
+ }
|
|
263
|
+ n.items = n.items[:i]
|
|
264
|
+ if !n.leaf() {
|
|
265
|
+ *n.children = (*n.children)[:i+1]
|
|
266
|
+ }
|
|
267
|
+ }
|
|
268
|
+ n.updateCount()
|
|
269
|
+
|
313
|
270
|
return right, median
|
314
|
271
|
}
|
315
|
272
|
|
316
|
|
-func (n *node) updateCount() {
|
|
273
|
+func (n *node[T]) updateCount() {
|
317
|
274
|
n.count = len(n.items)
|
318
|
275
|
if !n.leaf() {
|
319
|
276
|
for i := 0; i < len(*n.children); i++ {
|
|
@@ -326,33 +283,42 @@ func (n *node) updateCount() {
|
326
|
283
|
// called outside of heavy copy-on-write situations. Marking it "noinline"
|
327
|
284
|
// allows for the parent cowLoad to be inlined.
|
328
|
285
|
// go:noinline
|
329
|
|
-func (tr *bTree) copy(n *node) *node {
|
330
|
|
- n2 := new(node)
|
|
286
|
+func (tr *BTreeG[T]) copy(n *node[T]) *node[T] {
|
|
287
|
+ n2 := new(node[T])
|
331
|
288
|
n2.cow = tr.cow
|
332
|
289
|
n2.count = n.count
|
333
|
|
- n2.items = make([]kind, len(n.items), cap(n.items))
|
|
290
|
+ n2.items = make([]T, len(n.items), cap(n.items))
|
334
|
291
|
copy(n2.items, n.items)
|
335
|
292
|
if !n.leaf() {
|
336
|
|
- n2.children = new([]*node)
|
337
|
|
- *n2.children = make([]*node, len(*n.children), maxItems+1)
|
|
293
|
+ n2.children = new([]*node[T])
|
|
294
|
+ *n2.children = make([]*node[T], len(*n.children), maxItems+1)
|
338
|
295
|
copy(*n2.children, *n.children)
|
339
|
296
|
}
|
340
|
297
|
return n2
|
341
|
298
|
}
|
342
|
299
|
|
343
|
300
|
// cowLoad loads the provided node and, if needed, performs a copy-on-write.
|
344
|
|
-func (tr *bTree) cowLoad(cn **node) *node {
|
|
301
|
+func (tr *BTreeG[T]) cowLoad(cn **node[T]) *node[T] {
|
345
|
302
|
if (*cn).cow != tr.cow {
|
346
|
303
|
*cn = tr.copy(*cn)
|
347
|
304
|
}
|
348
|
305
|
return *cn
|
349
|
306
|
}
|
350
|
307
|
|
351
|
|
-func (tr *bTree) nodeSet(cn **node, item kind,
|
352
|
|
- hint *bPathHint, depth int,
|
353
|
|
-) (prev kind, replaced bool, split bool) {
|
354
|
|
- n := tr.cowLoad(cn)
|
355
|
|
- i, found := tr.find(n, item, hint, depth)
|
|
308
|
+func (tr *BTreeG[T]) nodeSet(cn **node[T], item T,
|
|
309
|
+ hint *PathHint, depth int,
|
|
310
|
+) (prev T, replaced bool, split bool) {
|
|
311
|
+ if (*cn).cow != tr.cow {
|
|
312
|
+ *cn = tr.copy(*cn)
|
|
313
|
+ }
|
|
314
|
+ n := *cn
|
|
315
|
+ var i int
|
|
316
|
+ var found bool
|
|
317
|
+ if hint == nil {
|
|
318
|
+ i, found = tr.bsearch(n, item)
|
|
319
|
+ } else {
|
|
320
|
+ i, found = tr.hintsearch(n, item, hint, depth)
|
|
321
|
+ }
|
356
|
322
|
if found {
|
357
|
323
|
prev = n.items[i]
|
358
|
324
|
n.items[i] = item
|
|
@@ -388,7 +354,7 @@ func (tr *bTree) nodeSet(cn **node, item kind,
|
388
|
354
|
return prev, replaced, false
|
389
|
355
|
}
|
390
|
356
|
|
391
|
|
-func (tr *bTree) Scan(iter func(item kind) bool) {
|
|
357
|
+func (tr *BTreeG[T]) Scan(iter func(item T) bool) {
|
392
|
358
|
if tr.rlock() {
|
393
|
359
|
defer tr.runlock()
|
394
|
360
|
}
|
|
@@ -398,7 +364,7 @@ func (tr *bTree) Scan(iter func(item kind) bool) {
|
398
|
364
|
tr.root.scan(iter)
|
399
|
365
|
}
|
400
|
366
|
|
401
|
|
-func (n *node) scan(iter func(item kind) bool) bool {
|
|
367
|
+func (n *node[T]) scan(iter func(item T) bool) bool {
|
402
|
368
|
if n.leaf() {
|
403
|
369
|
for i := 0; i < len(n.items); i++ {
|
404
|
370
|
if !iter(n.items[i]) {
|
|
@@ -419,15 +385,36 @@ func (n *node) scan(iter func(item kind) bool) bool {
|
419
|
385
|
}
|
420
|
386
|
|
421
|
387
|
// Get a value for key
|
422
|
|
-func (tr *bTree) Get(key kind) (kind, bool) {
|
423
|
|
- return tr.GetHint(key, nil)
|
|
388
|
+func (tr *BTreeG[T]) Get(key T) (T, bool) {
|
|
389
|
+ if tr.locks {
|
|
390
|
+ return tr.GetHint(key, nil)
|
|
391
|
+ }
|
|
392
|
+ if tr.root == nil {
|
|
393
|
+ return tr.empty, false
|
|
394
|
+ }
|
|
395
|
+ n := tr.root
|
|
396
|
+ for {
|
|
397
|
+ i, found := tr.bsearch(n, key)
|
|
398
|
+ if found {
|
|
399
|
+ return n.items[i], true
|
|
400
|
+ }
|
|
401
|
+ if n.children == nil {
|
|
402
|
+ return tr.empty, false
|
|
403
|
+ }
|
|
404
|
+ n = (*n.children)[i]
|
|
405
|
+ }
|
424
|
406
|
}
|
425
|
407
|
|
426
|
408
|
// GetHint gets a value for key using a path hint
|
427
|
|
-func (tr *bTree) GetHint(key kind, hint *bPathHint) (kind, bool) {
|
|
409
|
+func (tr *BTreeG[T]) GetHint(key T, hint *PathHint) (value T, ok bool) {
|
428
|
410
|
if tr.rlock() {
|
429
|
411
|
defer tr.runlock()
|
430
|
412
|
}
|
|
413
|
+ return tr.getHint(key, hint)
|
|
414
|
+}
|
|
415
|
+
|
|
416
|
+// GetHint gets a value for key using a path hint
|
|
417
|
+func (tr *BTreeG[T]) getHint(key T, hint *PathHint) (T, bool) {
|
431
|
418
|
if tr.root == nil {
|
432
|
419
|
return tr.empty, false
|
433
|
420
|
}
|
|
@@ -447,24 +434,27 @@ func (tr *bTree) GetHint(key kind, hint *bPathHint) (kind, bool) {
|
447
|
434
|
}
|
448
|
435
|
|
449
|
436
|
// Len returns the number of items in the tree
|
450
|
|
-func (tr *bTree) Len() int {
|
|
437
|
+func (tr *BTreeG[T]) Len() int {
|
451
|
438
|
return tr.count
|
452
|
439
|
}
|
453
|
440
|
|
454
|
|
-// Delete a value for a key
|
455
|
|
-func (tr *bTree) Delete(key kind) (kind, bool) {
|
|
441
|
+// Delete a value for a key and returns the deleted value.
|
|
442
|
+// Returns false if there was no value by that key found.
|
|
443
|
+func (tr *BTreeG[T]) Delete(key T) (T, bool) {
|
456
|
444
|
return tr.DeleteHint(key, nil)
|
457
|
445
|
}
|
458
|
446
|
|
459
|
|
-// DeleteHint deletes a value for a key using a path hint
|
460
|
|
-func (tr *bTree) DeleteHint(key kind, hint *bPathHint) (kind, bool) {
|
|
447
|
+// DeleteHint deletes a value for a key using a path hint and returns the
|
|
448
|
+// deleted value.
|
|
449
|
+// Returns false if there was no value by that key found.
|
|
450
|
+func (tr *BTreeG[T]) DeleteHint(key T, hint *PathHint) (T, bool) {
|
461
|
451
|
if tr.lock() {
|
462
|
452
|
defer tr.unlock()
|
463
|
453
|
}
|
464
|
454
|
return tr.deleteHint(key, hint)
|
465
|
455
|
}
|
466
|
456
|
|
467
|
|
-func (tr *bTree) deleteHint(key kind, hint *bPathHint) (kind, bool) {
|
|
457
|
+func (tr *BTreeG[T]) deleteHint(key T, hint *PathHint) (T, bool) {
|
468
|
458
|
if tr.root == nil {
|
469
|
459
|
return tr.empty, false
|
470
|
460
|
}
|
|
@@ -482,9 +472,9 @@ func (tr *bTree) deleteHint(key kind, hint *bPathHint) (kind, bool) {
|
482
|
472
|
return prev, true
|
483
|
473
|
}
|
484
|
474
|
|
485
|
|
-func (tr *bTree) delete(cn **node, max bool, key kind,
|
486
|
|
- hint *bPathHint, depth int,
|
487
|
|
-) (kind, bool) {
|
|
475
|
+func (tr *BTreeG[T]) delete(cn **node[T], max bool, key T,
|
|
476
|
+ hint *PathHint, depth int,
|
|
477
|
+) (T, bool) {
|
488
|
478
|
n := tr.cowLoad(cn)
|
489
|
479
|
var i int
|
490
|
480
|
var found bool
|
|
@@ -506,7 +496,7 @@ func (tr *bTree) delete(cn **node, max bool, key kind,
|
506
|
496
|
return tr.empty, false
|
507
|
497
|
}
|
508
|
498
|
|
509
|
|
- var prev kind
|
|
499
|
+ var prev T
|
510
|
500
|
var deleted bool
|
511
|
501
|
if found {
|
512
|
502
|
if max {
|
|
@@ -529,13 +519,12 @@ func (tr *bTree) delete(cn **node, max bool, key kind,
|
529
|
519
|
tr.nodeRebalance(n, i)
|
530
|
520
|
}
|
531
|
521
|
return prev, true
|
532
|
|
-
|
533
|
522
|
}
|
534
|
523
|
|
535
|
524
|
// nodeRebalance rebalances the child nodes following a delete operation.
|
536
|
525
|
// Provide the index of the child node with the number of items that fell
|
537
|
526
|
// below minItems.
|
538
|
|
-func (tr *bTree) nodeRebalance(n *node, i int) {
|
|
527
|
+func (tr *BTreeG[T]) nodeRebalance(n *node[T], i int) {
|
539
|
528
|
if i == len(n.items) {
|
540
|
529
|
i--
|
541
|
530
|
}
|
|
@@ -618,7 +607,7 @@ func (tr *bTree) nodeRebalance(n *node, i int) {
|
618
|
607
|
// Ascend the tree within the range [pivot, last]
|
619
|
608
|
// Pass nil for pivot to scan all item in ascending order
|
620
|
609
|
// Return false to stop iterating
|
621
|
|
-func (tr *bTree) Ascend(pivot kind, iter func(item kind) bool) {
|
|
610
|
+func (tr *BTreeG[T]) Ascend(pivot T, iter func(item T) bool) {
|
622
|
611
|
if tr.rlock() {
|
623
|
612
|
defer tr.runlock()
|
624
|
613
|
}
|
|
@@ -630,8 +619,8 @@ func (tr *bTree) Ascend(pivot kind, iter func(item kind) bool) {
|
630
|
619
|
|
631
|
620
|
// The return value of this function determines whether we should keep iterating
|
632
|
621
|
// upon this functions return.
|
633
|
|
-func (tr *bTree) ascend(n *node, pivot kind,
|
634
|
|
- hint *bPathHint, depth int, iter func(item kind) bool,
|
|
622
|
+func (tr *BTreeG[T]) ascend(n *node[T], pivot T,
|
|
623
|
+ hint *PathHint, depth int, iter func(item T) bool,
|
635
|
624
|
) bool {
|
636
|
625
|
i, found := tr.find(n, pivot, hint, depth)
|
637
|
626
|
if !found {
|
|
@@ -658,7 +647,7 @@ func (tr *bTree) ascend(n *node, pivot kind,
|
658
|
647
|
return true
|
659
|
648
|
}
|
660
|
649
|
|
661
|
|
-func (tr *bTree) Reverse(iter func(item kind) bool) {
|
|
650
|
+func (tr *BTreeG[T]) Reverse(iter func(item T) bool) {
|
662
|
651
|
if tr.rlock() {
|
663
|
652
|
defer tr.runlock()
|
664
|
653
|
}
|
|
@@ -668,7 +657,7 @@ func (tr *bTree) Reverse(iter func(item kind) bool) {
|
668
|
657
|
tr.root.reverse(iter)
|
669
|
658
|
}
|
670
|
659
|
|
671
|
|
-func (n *node) reverse(iter func(item kind) bool) bool {
|
|
660
|
+func (n *node[T]) reverse(iter func(item T) bool) bool {
|
672
|
661
|
if n.leaf() {
|
673
|
662
|
for i := len(n.items) - 1; i >= 0; i-- {
|
674
|
663
|
if !iter(n.items[i]) {
|
|
@@ -694,7 +683,7 @@ func (n *node) reverse(iter func(item kind) bool) bool {
|
694
|
683
|
// Descend the tree within the range [pivot, first]
|
695
|
684
|
// Pass nil for pivot to scan all item in descending order
|
696
|
685
|
// Return false to stop iterating
|
697
|
|
-func (tr *bTree) Descend(pivot kind, iter func(item kind) bool) {
|
|
686
|
+func (tr *BTreeG[T]) Descend(pivot T, iter func(item T) bool) {
|
698
|
687
|
if tr.rlock() {
|
699
|
688
|
defer tr.runlock()
|
700
|
689
|
}
|
|
@@ -704,8 +693,8 @@ func (tr *bTree) Descend(pivot kind, iter func(item kind) bool) {
|
704
|
693
|
tr.descend(tr.root, pivot, nil, 0, iter)
|
705
|
694
|
}
|
706
|
695
|
|
707
|
|
-func (tr *bTree) descend(n *node, pivot kind,
|
708
|
|
- hint *bPathHint, depth int, iter func(item kind) bool,
|
|
696
|
+func (tr *BTreeG[T]) descend(n *node[T], pivot T,
|
|
697
|
+ hint *PathHint, depth int, iter func(item T) bool,
|
709
|
698
|
) bool {
|
710
|
699
|
i, found := tr.find(n, pivot, hint, depth)
|
711
|
700
|
if !found {
|
|
@@ -730,7 +719,7 @@ func (tr *bTree) descend(n *node, pivot kind,
|
730
|
719
|
}
|
731
|
720
|
|
732
|
721
|
// Load is for bulk loading pre-sorted items
|
733
|
|
-func (tr *bTree) Load(item kind) (kind, bool) {
|
|
722
|
+func (tr *BTreeG[T]) Load(item T) (T, bool) {
|
734
|
723
|
if tr.lock() {
|
735
|
724
|
defer tr.unlock()
|
736
|
725
|
}
|
|
@@ -765,8 +754,8 @@ func (tr *bTree) Load(item kind) (kind, bool) {
|
765
|
754
|
}
|
766
|
755
|
|
767
|
756
|
// Min returns the minimum item in tree.
|
768
|
|
-// Returns nil if the tree has no items.
|
769
|
|
-func (tr *bTree) Min() (kind, bool) {
|
|
757
|
+// Returns nil if the treex has no items.
|
|
758
|
+func (tr *BTreeG[T]) Min() (T, bool) {
|
770
|
759
|
if tr.rlock() {
|
771
|
760
|
defer tr.runlock()
|
772
|
761
|
}
|
|
@@ -784,7 +773,7 @@ func (tr *bTree) Min() (kind, bool) {
|
784
|
773
|
|
785
|
774
|
// Max returns the maximum item in tree.
|
786
|
775
|
// Returns nil if the tree has no items.
|
787
|
|
-func (tr *bTree) Max() (kind, bool) {
|
|
776
|
+func (tr *BTreeG[T]) Max() (T, bool) {
|
788
|
777
|
if tr.rlock() {
|
789
|
778
|
defer tr.runlock()
|
790
|
779
|
}
|
|
@@ -802,7 +791,7 @@ func (tr *bTree) Max() (kind, bool) {
|
802
|
791
|
|
803
|
792
|
// PopMin removes the minimum item in tree and returns it.
|
804
|
793
|
// Returns nil if the tree has no items.
|
805
|
|
-func (tr *bTree) PopMin() (kind, bool) {
|
|
794
|
+func (tr *BTreeG[T]) PopMin() (T, bool) {
|
806
|
795
|
if tr.lock() {
|
807
|
796
|
defer tr.unlock()
|
808
|
797
|
}
|
|
@@ -810,7 +799,7 @@ func (tr *bTree) PopMin() (kind, bool) {
|
810
|
799
|
return tr.empty, false
|
811
|
800
|
}
|
812
|
801
|
n := tr.cowLoad(&tr.root)
|
813
|
|
- var item kind
|
|
802
|
+ var item T
|
814
|
803
|
for {
|
815
|
804
|
n.count-- // optimistically update counts
|
816
|
805
|
if n.leaf() {
|
|
@@ -841,9 +830,9 @@ func (tr *bTree) PopMin() (kind, bool) {
|
841
|
830
|
return tr.deleteHint(item, nil)
|
842
|
831
|
}
|
843
|
832
|
|
844
|
|
-// PopMax removes the minimum item in tree and returns it.
|
|
833
|
+// PopMax removes the maximum item in tree and returns it.
|
845
|
834
|
// Returns nil if the tree has no items.
|
846
|
|
-func (tr *bTree) PopMax() (kind, bool) {
|
|
835
|
+func (tr *BTreeG[T]) PopMax() (T, bool) {
|
847
|
836
|
if tr.lock() {
|
848
|
837
|
defer tr.unlock()
|
849
|
838
|
}
|
|
@@ -851,7 +840,7 @@ func (tr *bTree) PopMax() (kind, bool) {
|
851
|
840
|
return tr.empty, false
|
852
|
841
|
}
|
853
|
842
|
n := tr.cowLoad(&tr.root)
|
854
|
|
- var item kind
|
|
843
|
+ var item T
|
855
|
844
|
for {
|
856
|
845
|
n.count-- // optimistically update counts
|
857
|
846
|
if n.leaf() {
|
|
@@ -883,7 +872,7 @@ func (tr *bTree) PopMax() (kind, bool) {
|
883
|
872
|
|
884
|
873
|
// GetAt returns the value at index.
|
885
|
874
|
// Return nil if the tree is empty or the index is out of bounds.
|
886
|
|
-func (tr *bTree) GetAt(index int) (kind, bool) {
|
|
875
|
+func (tr *BTreeG[T]) GetAt(index int) (T, bool) {
|
887
|
876
|
if tr.rlock() {
|
888
|
877
|
defer tr.runlock()
|
889
|
878
|
}
|
|
@@ -910,7 +899,7 @@ func (tr *bTree) GetAt(index int) (kind, bool) {
|
910
|
899
|
|
911
|
900
|
// DeleteAt deletes the item at index.
|
912
|
901
|
// Return nil if the tree is empty or the index is out of bounds.
|
913
|
|
-func (tr *bTree) DeleteAt(index int) (kind, bool) {
|
|
902
|
+func (tr *BTreeG[T]) DeleteAt(index int) (T, bool) {
|
914
|
903
|
if tr.lock() {
|
915
|
904
|
defer tr.unlock()
|
916
|
905
|
}
|
|
@@ -919,7 +908,7 @@ func (tr *bTree) DeleteAt(index int) (kind, bool) {
|
919
|
908
|
}
|
920
|
909
|
var pathbuf [8]uint8 // track the path
|
921
|
910
|
path := pathbuf[:0]
|
922
|
|
- var item kind
|
|
911
|
+ var item T
|
923
|
912
|
n := tr.cowLoad(&tr.root)
|
924
|
913
|
outer:
|
925
|
914
|
for {
|
|
@@ -955,7 +944,7 @@ outer:
|
955
|
944
|
n = tr.cowLoad(&(*n.children)[i])
|
956
|
945
|
}
|
957
|
946
|
// revert the counts
|
958
|
|
- var hint bPathHint
|
|
947
|
+ var hint PathHint
|
959
|
948
|
n = tr.root
|
960
|
949
|
for i := 0; i < len(path); i++ {
|
961
|
950
|
if i < len(hint.path) {
|
|
@@ -972,7 +961,7 @@ outer:
|
972
|
961
|
|
973
|
962
|
// Height returns the height of the tree.
|
974
|
963
|
// Returns zero if tree has no items.
|
975
|
|
-func (tr *bTree) Height() int {
|
|
964
|
+func (tr *BTreeG[T]) Height() int {
|
976
|
965
|
if tr.rlock() {
|
977
|
966
|
defer tr.runlock()
|
978
|
967
|
}
|
|
@@ -992,7 +981,7 @@ func (tr *bTree) Height() int {
|
992
|
981
|
|
993
|
982
|
// Walk iterates over all items in tree, in order.
|
994
|
983
|
// The items param will contain one or more items.
|
995
|
|
-func (tr *bTree) Walk(iter func(item []kind) bool) {
|
|
984
|
+func (tr *BTreeG[T]) Walk(iter func(item []T) bool) {
|
996
|
985
|
if tr.rlock() {
|
997
|
986
|
defer tr.runlock()
|
998
|
987
|
}
|
|
@@ -1001,7 +990,7 @@ func (tr *bTree) Walk(iter func(item []kind) bool) {
|
1001
|
990
|
}
|
1002
|
991
|
}
|
1003
|
992
|
|
1004
|
|
-func (n *node) walk(iter func(item []kind) bool) bool {
|
|
993
|
+func (n *node[T]) walk(iter func(item []T) bool) bool {
|
1005
|
994
|
if n.leaf() {
|
1006
|
995
|
if !iter(n.items) {
|
1007
|
996
|
return false
|
|
@@ -1020,60 +1009,60 @@ func (n *node) walk(iter func(item []kind) bool) bool {
|
1020
|
1009
|
|
1021
|
1010
|
// Copy the tree. This is a copy-on-write operation and is very fast because
|
1022
|
1011
|
// it only performs a shadowed copy.
|
1023
|
|
-func (tr *bTree) Copy() *bTree {
|
|
1012
|
+func (tr *BTreeG[T]) Copy() *BTreeG[T] {
|
1024
|
1013
|
if tr.lock() {
|
1025
|
1014
|
defer tr.unlock()
|
1026
|
1015
|
}
|
1027
|
|
- tr.cow = new(cow)
|
1028
|
|
- tr2 := new(bTree)
|
|
1016
|
+ tr.cow = atomic.AddUint64(&gcow, 1)
|
|
1017
|
+ tr2 := new(BTreeG[T])
|
1029
|
1018
|
*tr2 = *tr
|
1030
|
1019
|
tr2.mu = new(sync.RWMutex)
|
1031
|
|
- tr2.cow = new(cow)
|
|
1020
|
+ tr2.cow = atomic.AddUint64(&gcow, 1)
|
1032
|
1021
|
return tr2
|
1033
|
1022
|
}
|
1034
|
1023
|
|
1035
|
|
-func (tr *bTree) lock() bool {
|
|
1024
|
+func (tr *BTreeG[T]) lock() bool {
|
1036
|
1025
|
if tr.locks {
|
1037
|
1026
|
tr.mu.Lock()
|
1038
|
1027
|
}
|
1039
|
1028
|
return tr.locks
|
1040
|
1029
|
}
|
1041
|
1030
|
|
1042
|
|
-func (tr *bTree) unlock() {
|
|
1031
|
+func (tr *BTreeG[T]) unlock() {
|
1043
|
1032
|
tr.mu.Unlock()
|
1044
|
1033
|
}
|
1045
|
1034
|
|
1046
|
|
-func (tr *bTree) rlock() bool {
|
|
1035
|
+func (tr *BTreeG[T]) rlock() bool {
|
1047
|
1036
|
if tr.locks {
|
1048
|
1037
|
tr.mu.RLock()
|
1049
|
1038
|
}
|
1050
|
1039
|
return tr.locks
|
1051
|
1040
|
}
|
1052
|
1041
|
|
1053
|
|
-func (tr *bTree) runlock() {
|
|
1042
|
+func (tr *BTreeG[T]) runlock() {
|
1054
|
1043
|
tr.mu.RUnlock()
|
1055
|
1044
|
}
|
1056
|
1045
|
|
1057
|
1046
|
// Iter represents an iterator
|
1058
|
|
-type bIter struct {
|
1059
|
|
- tr *bTree
|
|
1047
|
+type GenericIter[T any] struct {
|
|
1048
|
+ tr *BTreeG[T]
|
1060
|
1049
|
locked bool
|
1061
|
1050
|
seeked bool
|
1062
|
1051
|
atstart bool
|
1063
|
1052
|
atend bool
|
1064
|
|
- stack []iterStackItem
|
1065
|
|
- item kind
|
|
1053
|
+ stack []genericIterStackItem[T]
|
|
1054
|
+ item T
|
1066
|
1055
|
}
|
1067
|
1056
|
|
1068
|
|
-type iterStackItem struct {
|
1069
|
|
- n *node
|
|
1057
|
+type genericIterStackItem[T any] struct {
|
|
1058
|
+ n *node[T]
|
1070
|
1059
|
i int
|
1071
|
1060
|
}
|
1072
|
1061
|
|
1073
|
1062
|
// Iter returns a read-only iterator.
|
1074
|
1063
|
// The Release method must be called finished with iterator.
|
1075
|
|
-func (tr *bTree) Iter() bIter {
|
1076
|
|
- var iter bIter
|
|
1064
|
+func (tr *BTreeG[T]) Iter() GenericIter[T] {
|
|
1065
|
+ var iter GenericIter[T]
|
1077
|
1066
|
iter.tr = tr
|
1078
|
1067
|
iter.locked = tr.rlock()
|
1079
|
1068
|
return iter
|
|
@@ -1081,7 +1070,7 @@ func (tr *bTree) Iter() bIter {
|
1081
|
1070
|
|
1082
|
1071
|
// Seek to item greater-or-equal-to key.
|
1083
|
1072
|
// Returns false if there was no item found.
|
1084
|
|
-func (iter *bIter) Seek(key kind) bool {
|
|
1073
|
+func (iter *GenericIter[T]) Seek(key T) bool {
|
1085
|
1074
|
if iter.tr == nil {
|
1086
|
1075
|
return false
|
1087
|
1076
|
}
|
|
@@ -1093,16 +1082,14 @@ func (iter *bIter) Seek(key kind) bool {
|
1093
|
1082
|
n := iter.tr.root
|
1094
|
1083
|
for {
|
1095
|
1084
|
i, found := iter.tr.find(n, key, nil, 0)
|
1096
|
|
- iter.stack = append(iter.stack, iterStackItem{n, i})
|
|
1085
|
+ iter.stack = append(iter.stack, genericIterStackItem[T]{n, i})
|
1097
|
1086
|
if found {
|
|
1087
|
+ iter.item = n.items[i]
|
1098
|
1088
|
return true
|
1099
|
1089
|
}
|
1100
|
1090
|
if n.leaf() {
|
1101
|
|
- if i == len(n.items) {
|
1102
|
|
- iter.stack = iter.stack[:0]
|
1103
|
|
- return false
|
1104
|
|
- }
|
1105
|
|
- return true
|
|
1091
|
+ iter.stack[len(iter.stack)-1].i--
|
|
1092
|
+ return iter.Next()
|
1106
|
1093
|
}
|
1107
|
1094
|
n = (*n.children)[i]
|
1108
|
1095
|
}
|
|
@@ -1110,7 +1097,7 @@ func (iter *bIter) Seek(key kind) bool {
|
1110
|
1097
|
|
1111
|
1098
|
// First moves iterator to first item in tree.
|
1112
|
1099
|
// Returns false if the tree is empty.
|
1113
|
|
-func (iter *bIter) First() bool {
|
|
1100
|
+func (iter *GenericIter[T]) First() bool {
|
1114
|
1101
|
if iter.tr == nil {
|
1115
|
1102
|
return false
|
1116
|
1103
|
}
|
|
@@ -1123,7 +1110,7 @@ func (iter *bIter) First() bool {
|
1123
|
1110
|
}
|
1124
|
1111
|
n := iter.tr.root
|
1125
|
1112
|
for {
|
1126
|
|
- iter.stack = append(iter.stack, iterStackItem{n, 0})
|
|
1113
|
+ iter.stack = append(iter.stack, genericIterStackItem[T]{n, 0})
|
1127
|
1114
|
if n.leaf() {
|
1128
|
1115
|
break
|
1129
|
1116
|
}
|
|
@@ -1136,7 +1123,7 @@ func (iter *bIter) First() bool {
|
1136
|
1123
|
|
1137
|
1124
|
// Last moves iterator to last item in tree.
|
1138
|
1125
|
// Returns false if the tree is empty.
|
1139
|
|
-func (iter *bIter) Last() bool {
|
|
1126
|
+func (iter *GenericIter[T]) Last() bool {
|
1140
|
1127
|
if iter.tr == nil {
|
1141
|
1128
|
return false
|
1142
|
1129
|
}
|
|
@@ -1147,7 +1134,7 @@ func (iter *bIter) Last() bool {
|
1147
|
1134
|
}
|
1148
|
1135
|
n := iter.tr.root
|
1149
|
1136
|
for {
|
1150
|
|
- iter.stack = append(iter.stack, iterStackItem{n, len(n.items)})
|
|
1137
|
+ iter.stack = append(iter.stack, genericIterStackItem[T]{n, len(n.items)})
|
1151
|
1138
|
if n.leaf() {
|
1152
|
1139
|
iter.stack[len(iter.stack)-1].i--
|
1153
|
1140
|
break
|
|
@@ -1159,9 +1146,8 @@ func (iter *bIter) Last() bool {
|
1159
|
1146
|
return true
|
1160
|
1147
|
}
|
1161
|
1148
|
|
1162
|
|
-// First moves iterator to first item in tree.
|
1163
|
|
-// Returns false if the tree is empty.
|
1164
|
|
-func (iter *bIter) Release() {
|
|
1149
|
+// Release the iterator.
|
|
1150
|
+func (iter *GenericIter[T]) Release() {
|
1165
|
1151
|
if iter.tr == nil {
|
1166
|
1152
|
return
|
1167
|
1153
|
}
|
|
@@ -1176,7 +1162,7 @@ func (iter *bIter) Release() {
|
1176
|
1162
|
// Next moves iterator to the next item in iterator.
|
1177
|
1163
|
// Returns false if the tree is empty or the iterator is at the end of
|
1178
|
1164
|
// the tree.
|
1179
|
|
-func (iter *bIter) Next() bool {
|
|
1165
|
+func (iter *GenericIter[T]) Next() bool {
|
1180
|
1166
|
if iter.tr == nil {
|
1181
|
1167
|
return false
|
1182
|
1168
|
}
|
|
@@ -1208,7 +1194,7 @@ func (iter *bIter) Next() bool {
|
1208
|
1194
|
} else {
|
1209
|
1195
|
n := (*s.n.children)[s.i]
|
1210
|
1196
|
for {
|
1211
|
|
- iter.stack = append(iter.stack, iterStackItem{n, 0})
|
|
1197
|
+ iter.stack = append(iter.stack, genericIterStackItem[T]{n, 0})
|
1212
|
1198
|
if n.leaf() {
|
1213
|
1199
|
break
|
1214
|
1200
|
}
|
|
@@ -1223,7 +1209,7 @@ func (iter *bIter) Next() bool {
|
1223
|
1209
|
// Prev moves iterator to the previous item in iterator.
|
1224
|
1210
|
// Returns false if the tree is empty or the iterator is at the beginning of
|
1225
|
1211
|
// the tree.
|
1226
|
|
-func (iter *bIter) Prev() bool {
|
|
1212
|
+func (iter *GenericIter[T]) Prev() bool {
|
1227
|
1213
|
if iter.tr == nil {
|
1228
|
1214
|
return false
|
1229
|
1215
|
}
|
|
@@ -1256,7 +1242,7 @@ func (iter *bIter) Prev() bool {
|
1256
|
1242
|
} else {
|
1257
|
1243
|
n := (*s.n.children)[s.i]
|
1258
|
1244
|
for {
|
1259
|
|
- iter.stack = append(iter.stack, iterStackItem{n, len(n.items)})
|
|
1245
|
+ iter.stack = append(iter.stack, genericIterStackItem[T]{n, len(n.items)})
|
1260
|
1246
|
if n.leaf() {
|
1261
|
1247
|
iter.stack[len(iter.stack)-1].i--
|
1262
|
1248
|
break
|
|
@@ -1270,6 +1256,48 @@ func (iter *bIter) Prev() bool {
|
1270
|
1256
|
}
|
1271
|
1257
|
|
1272
|
1258
|
// Item returns the current iterator item.
|
1273
|
|
-func (iter *bIter) Item() kind {
|
|
1259
|
+func (iter *GenericIter[T]) Item() T {
|
1274
|
1260
|
return iter.item
|
1275
|
1261
|
}
|
|
1262
|
+
|
|
1263
|
+// Items returns all the items in order.
|
|
1264
|
+func (tr *BTreeG[T]) Items() []T {
|
|
1265
|
+ items := make([]T, 0, tr.Len())
|
|
1266
|
+ if tr.root != nil {
|
|
1267
|
+ items = tr.root.aitems(items)
|
|
1268
|
+ }
|
|
1269
|
+ return items
|
|
1270
|
+}
|
|
1271
|
+
|
|
1272
|
+func (n *node[T]) aitems(items []T) []T {
|
|
1273
|
+ if n.leaf() {
|
|
1274
|
+ return append(items, n.items...)
|
|
1275
|
+ }
|
|
1276
|
+ for i := 0; i < len(n.items); i++ {
|
|
1277
|
+ items = (*n.children)[i].aitems(items)
|
|
1278
|
+ items = append(items, n.items[i])
|
|
1279
|
+ }
|
|
1280
|
+ return (*n.children)[len(*n.children)-1].aitems(items)
|
|
1281
|
+}
|
|
1282
|
+
|
|
1283
|
+// Generic BTree
|
|
1284
|
+// Deprecated: use BTreeG
|
|
1285
|
+type Generic[T any] struct {
|
|
1286
|
+ *BTreeG[T]
|
|
1287
|
+}
|
|
1288
|
+
|
|
1289
|
+// NewGeneric returns a generic BTree
|
|
1290
|
+// Deprecated: use NewBTreeG
|
|
1291
|
+func NewGeneric[T any](less func(a, b T) bool) *Generic[T] {
|
|
1292
|
+ return &Generic[T]{NewBTreeGOptions(less, Options{})}
|
|
1293
|
+}
|
|
1294
|
+
|
|
1295
|
+// NewGenericOptions returns a generic BTree
|
|
1296
|
+// Deprecated: use NewBTreeGOptions
|
|
1297
|
+func NewGenericOptions[T any](less func(a, b T) bool, opts Options) *Generic[T] {
|
|
1298
|
+ return &Generic[T]{NewBTreeGOptions(less, opts)}
|
|
1299
|
+}
|
|
1300
|
+
|
|
1301
|
+func (tr *Generic[T]) Copy() *Generic[T] {
|
|
1302
|
+ return &Generic[T]{tr.BTreeG.Copy()}
|
|
1303
|
+}
|