Codebase list golang-github-google-btree / c5e38f0
Import upstream version 1.1.2 Debian Janitor 1 year, 4 months ago
8 changed file(s) with 1905 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
0 on: [push, pull_request]
1 name: Test
2 jobs:
3 test:
4 strategy:
5 matrix:
6 go-version:
7 - 1.11.x
8 - 1.12.x
9 - 1.13.x
10 - 1.14.x
11 - 1.15.x
12 - 1.16.x
13 - 1.17.x
14 - 1.18.x
15 os:
16 - ubuntu-latest
17 runs-on: ${{ matrix.os }}
18 steps:
19 - name: Install Go
20 uses: actions/setup-go@v2
21 with:
22 go-version: ${{ matrix.go-version }}
23 - name: Checkout code
24 uses: actions/checkout@v2
25 - name: Test
26 run: go test -v ./...
+0
-1
.travis.yml less more
0 language: go
00 # BTree implementation for Go
1
2 ![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master)
31
42 This package provides an in-memory B-Tree implementation for Go, useful as
53 an ordered, mutable data structure.
1010 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1111 // See the License for the specific language governing permissions and
1212 // limitations under the License.
13
14 //go:build !go1.18
15 // +build !go1.18
1316
1417 // Package btree implements in-memory B-Trees of arbitrary degree.
1518 //
795798 }
796799
797800 // DescendGreaterThan calls the iterator for every value in the tree within
798 // the range (pivot, last], until iterator returns false.
801 // the range [last, pivot), until iterator returns false.
799802 func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) {
800803 if t.root == nil {
801804 return
0 // Copyright 2014-2022 Google Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 //go:build go1.18
15 // +build go1.18
16
17 // In Go 1.18 and beyond, a BTreeG generic is created, and BTree is a specific
18 // instantiation of that generic for the Item interface, with a backwards-
19 // compatible API. Before go1.18, generics are not supported,
20 // and BTree is just an implementation based around the Item interface.
21
22 // Package btree implements in-memory B-Trees of arbitrary degree.
23 //
24 // btree implements an in-memory B-Tree for use as an ordered data structure.
25 // It is not meant for persistent storage solutions.
26 //
27 // It has a flatter structure than an equivalent red-black or other binary tree,
28 // which in some cases yields better memory usage and/or performance.
29 // See some discussion on the matter here:
30 // http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html
31 // Note, though, that this project is in no way related to the C++ B-Tree
32 // implementation written about there.
33 //
34 // Within this tree, each node contains a slice of items and a (possibly nil)
35 // slice of children. For basic numeric values or raw structs, this can cause
36 // efficiency differences when compared to equivalent C++ template code that
37 // stores values in arrays within the node:
38 // * Due to the overhead of storing values as interfaces (each
39 // value needs to be stored as the value itself, then 2 words for the
40 // interface pointing to that value and its type), resulting in higher
41 // memory use.
42 // * Since interfaces can point to values anywhere in memory, values are
43 // most likely not stored in contiguous blocks, resulting in a higher
44 // number of cache misses.
45 // These issues don't tend to matter, though, when working with strings or other
46 // heap-allocated structures, since C++-equivalent structures also must store
47 // pointers and also distribute their values across the heap.
48 //
49 // This implementation is designed to be a drop-in replacement to gollrb.LLRB
50 // trees, (http://github.com/petar/gollrb), an excellent and probably the most
51 // widely used ordered tree implementation in the Go ecosystem currently.
52 // Its functions, therefore, exactly mirror those of
53 // llrb.LLRB where possible. Unlike gollrb, though, we currently don't
54 // support storing multiple equivalent values.
55 //
56 // There are two implementations; those suffixed with 'G' are generics, usable
57 // for any type, and require a passed-in "less" function to define their ordering.
58 // Those without this prefix are specific to the 'Item' interface, and use
59 // its 'Less' function for ordering.
60 package btree
61
62 import (
63 "fmt"
64 "io"
65 "sort"
66 "strings"
67 "sync"
68 )
69
70 // Item represents a single object in the tree.
71 type Item interface {
72 // Less tests whether the current item is less than the given argument.
73 //
74 // This must provide a strict weak ordering.
75 // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only
76 // hold one of either a or b in the tree).
77 Less(than Item) bool
78 }
79
80 const (
81 DefaultFreeListSize = 32
82 )
83
84 // FreeListG represents a free list of btree nodes. By default each
85 // BTree has its own FreeList, but multiple BTrees can share the same
86 // FreeList, in particular when they're created with Clone.
87 // Two Btrees using the same freelist are safe for concurrent write access.
88 type FreeListG[T any] struct {
89 mu sync.Mutex
90 freelist []*node[T]
91 }
92
93 // NewFreeListG creates a new free list.
94 // size is the maximum size of the returned free list.
95 func NewFreeListG[T any](size int) *FreeListG[T] {
96 return &FreeListG[T]{freelist: make([]*node[T], 0, size)}
97 }
98
99 func (f *FreeListG[T]) newNode() (n *node[T]) {
100 f.mu.Lock()
101 index := len(f.freelist) - 1
102 if index < 0 {
103 f.mu.Unlock()
104 return new(node[T])
105 }
106 n = f.freelist[index]
107 f.freelist[index] = nil
108 f.freelist = f.freelist[:index]
109 f.mu.Unlock()
110 return
111 }
112
113 func (f *FreeListG[T]) freeNode(n *node[T]) (out bool) {
114 f.mu.Lock()
115 if len(f.freelist) < cap(f.freelist) {
116 f.freelist = append(f.freelist, n)
117 out = true
118 }
119 f.mu.Unlock()
120 return
121 }
122
123 // ItemIteratorG allows callers of {A/De}scend* to iterate in-order over portions of
124 // the tree. When this function returns false, iteration will stop and the
125 // associated Ascend* function will immediately return.
126 type ItemIteratorG[T any] func(item T) bool
127
128 // Ordered represents the set of types for which the '<' operator work.
129 type Ordered interface {
130 ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 | ~string
131 }
132
133 // Less[T] returns a default LessFunc that uses the '<' operator for types that support it.
134 func Less[T Ordered]() LessFunc[T] {
135 return func(a, b T) bool { return a < b }
136 }
137
138 // NewOrderedG creates a new B-Tree for ordered types.
139 func NewOrderedG[T Ordered](degree int) *BTreeG[T] {
140 return NewG[T](degree, Less[T]())
141 }
142
143 // NewG creates a new B-Tree with the given degree.
144 //
145 // NewG(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
146 // and 2-4 children).
147 //
148 // The passed-in LessFunc determines how objects of type T are ordered.
149 func NewG[T any](degree int, less LessFunc[T]) *BTreeG[T] {
150 return NewWithFreeListG(degree, less, NewFreeListG[T](DefaultFreeListSize))
151 }
152
153 // NewWithFreeListG creates a new B-Tree that uses the given node free list.
154 func NewWithFreeListG[T any](degree int, less LessFunc[T], f *FreeListG[T]) *BTreeG[T] {
155 if degree <= 1 {
156 panic("bad degree")
157 }
158 return &BTreeG[T]{
159 degree: degree,
160 cow: &copyOnWriteContext[T]{freelist: f, less: less},
161 }
162 }
163
164 // items stores items in a node.
165 type items[T any] []T
166
167 // insertAt inserts a value into the given index, pushing all subsequent values
168 // forward.
169 func (s *items[T]) insertAt(index int, item T) {
170 var zero T
171 *s = append(*s, zero)
172 if index < len(*s) {
173 copy((*s)[index+1:], (*s)[index:])
174 }
175 (*s)[index] = item
176 }
177
178 // removeAt removes a value at a given index, pulling all subsequent values
179 // back.
180 func (s *items[T]) removeAt(index int) T {
181 item := (*s)[index]
182 copy((*s)[index:], (*s)[index+1:])
183 var zero T
184 (*s)[len(*s)-1] = zero
185 *s = (*s)[:len(*s)-1]
186 return item
187 }
188
189 // pop removes and returns the last element in the list.
190 func (s *items[T]) pop() (out T) {
191 index := len(*s) - 1
192 out = (*s)[index]
193 var zero T
194 (*s)[index] = zero
195 *s = (*s)[:index]
196 return
197 }
198
199 // truncate truncates this instance at index so that it contains only the
200 // first index items. index must be less than or equal to length.
201 func (s *items[T]) truncate(index int) {
202 var toClear items[T]
203 *s, toClear = (*s)[:index], (*s)[index:]
204 var zero T
205 for i := 0; i < len(toClear); i++ {
206 toClear[i] = zero
207 }
208 }
209
210 // find returns the index where the given item should be inserted into this
211 // list. 'found' is true if the item already exists in the list at the given
212 // index.
213 func (s items[T]) find(item T, less func(T, T) bool) (index int, found bool) {
214 i := sort.Search(len(s), func(i int) bool {
215 return less(item, s[i])
216 })
217 if i > 0 && !less(s[i-1], item) {
218 return i - 1, true
219 }
220 return i, false
221 }
222
223 // node is an internal node in a tree.
224 //
225 // It must at all times maintain the invariant that either
226 // * len(children) == 0, len(items) unconstrained
227 // * len(children) == len(items) + 1
228 type node[T any] struct {
229 items items[T]
230 children items[*node[T]]
231 cow *copyOnWriteContext[T]
232 }
233
234 func (n *node[T]) mutableFor(cow *copyOnWriteContext[T]) *node[T] {
235 if n.cow == cow {
236 return n
237 }
238 out := cow.newNode()
239 if cap(out.items) >= len(n.items) {
240 out.items = out.items[:len(n.items)]
241 } else {
242 out.items = make(items[T], len(n.items), cap(n.items))
243 }
244 copy(out.items, n.items)
245 // Copy children
246 if cap(out.children) >= len(n.children) {
247 out.children = out.children[:len(n.children)]
248 } else {
249 out.children = make(items[*node[T]], len(n.children), cap(n.children))
250 }
251 copy(out.children, n.children)
252 return out
253 }
254
255 func (n *node[T]) mutableChild(i int) *node[T] {
256 c := n.children[i].mutableFor(n.cow)
257 n.children[i] = c
258 return c
259 }
260
261 // split splits the given node at the given index. The current node shrinks,
262 // and this function returns the item that existed at that index and a new node
263 // containing all items/children after it.
264 func (n *node[T]) split(i int) (T, *node[T]) {
265 item := n.items[i]
266 next := n.cow.newNode()
267 next.items = append(next.items, n.items[i+1:]...)
268 n.items.truncate(i)
269 if len(n.children) > 0 {
270 next.children = append(next.children, n.children[i+1:]...)
271 n.children.truncate(i + 1)
272 }
273 return item, next
274 }
275
276 // maybeSplitChild checks if a child should be split, and if so splits it.
277 // Returns whether or not a split occurred.
278 func (n *node[T]) maybeSplitChild(i, maxItems int) bool {
279 if len(n.children[i].items) < maxItems {
280 return false
281 }
282 first := n.mutableChild(i)
283 item, second := first.split(maxItems / 2)
284 n.items.insertAt(i, item)
285 n.children.insertAt(i+1, second)
286 return true
287 }
288
289 // insert inserts an item into the subtree rooted at this node, making sure
290 // no nodes in the subtree exceed maxItems items. Should an equivalent item be
291 // be found/replaced by insert, it will be returned.
292 func (n *node[T]) insert(item T, maxItems int) (_ T, _ bool) {
293 i, found := n.items.find(item, n.cow.less)
294 if found {
295 out := n.items[i]
296 n.items[i] = item
297 return out, true
298 }
299 if len(n.children) == 0 {
300 n.items.insertAt(i, item)
301 return
302 }
303 if n.maybeSplitChild(i, maxItems) {
304 inTree := n.items[i]
305 switch {
306 case n.cow.less(item, inTree):
307 // no change, we want first split node
308 case n.cow.less(inTree, item):
309 i++ // we want second split node
310 default:
311 out := n.items[i]
312 n.items[i] = item
313 return out, true
314 }
315 }
316 return n.mutableChild(i).insert(item, maxItems)
317 }
318
319 // get finds the given key in the subtree and returns it.
320 func (n *node[T]) get(key T) (_ T, _ bool) {
321 i, found := n.items.find(key, n.cow.less)
322 if found {
323 return n.items[i], true
324 } else if len(n.children) > 0 {
325 return n.children[i].get(key)
326 }
327 return
328 }
329
330 // min returns the first item in the subtree.
331 func min[T any](n *node[T]) (_ T, found bool) {
332 if n == nil {
333 return
334 }
335 for len(n.children) > 0 {
336 n = n.children[0]
337 }
338 if len(n.items) == 0 {
339 return
340 }
341 return n.items[0], true
342 }
343
344 // max returns the last item in the subtree.
345 func max[T any](n *node[T]) (_ T, found bool) {
346 if n == nil {
347 return
348 }
349 for len(n.children) > 0 {
350 n = n.children[len(n.children)-1]
351 }
352 if len(n.items) == 0 {
353 return
354 }
355 return n.items[len(n.items)-1], true
356 }
357
358 // toRemove details what item to remove in a node.remove call.
359 type toRemove int
360
361 const (
362 removeItem toRemove = iota // removes the given item
363 removeMin // removes smallest item in the subtree
364 removeMax // removes largest item in the subtree
365 )
366
367 // remove removes an item from the subtree rooted at this node.
368 func (n *node[T]) remove(item T, minItems int, typ toRemove) (_ T, _ bool) {
369 var i int
370 var found bool
371 switch typ {
372 case removeMax:
373 if len(n.children) == 0 {
374 return n.items.pop(), true
375 }
376 i = len(n.items)
377 case removeMin:
378 if len(n.children) == 0 {
379 return n.items.removeAt(0), true
380 }
381 i = 0
382 case removeItem:
383 i, found = n.items.find(item, n.cow.less)
384 if len(n.children) == 0 {
385 if found {
386 return n.items.removeAt(i), true
387 }
388 return
389 }
390 default:
391 panic("invalid type")
392 }
393 // If we get to here, we have children.
394 if len(n.children[i].items) <= minItems {
395 return n.growChildAndRemove(i, item, minItems, typ)
396 }
397 child := n.mutableChild(i)
398 // Either we had enough items to begin with, or we've done some
399 // merging/stealing, because we've got enough now and we're ready to return
400 // stuff.
401 if found {
402 // The item exists at index 'i', and the child we've selected can give us a
403 // predecessor, since if we've gotten here it's got > minItems items in it.
404 out := n.items[i]
405 // We use our special-case 'remove' call with typ=maxItem to pull the
406 // predecessor of item i (the rightmost leaf of our immediate left child)
407 // and set it into where we pulled the item from.
408 var zero T
409 n.items[i], _ = child.remove(zero, minItems, removeMax)
410 return out, true
411 }
412 // Final recursive call. Once we're here, we know that the item isn't in this
413 // node and that the child is big enough to remove from.
414 return child.remove(item, minItems, typ)
415 }
416
417 // growChildAndRemove grows child 'i' to make sure it's possible to remove an
418 // item from it while keeping it at minItems, then calls remove to actually
419 // remove it.
420 //
421 // Most documentation says we have to do two sets of special casing:
422 // 1) item is in this node
423 // 2) item is in child
424 // In both cases, we need to handle the two subcases:
425 // A) node has enough values that it can spare one
426 // B) node doesn't have enough values
427 // For the latter, we have to check:
428 // a) left sibling has node to spare
429 // b) right sibling has node to spare
430 // c) we must merge
431 // To simplify our code here, we handle cases #1 and #2 the same:
432 // If a node doesn't have enough items, we make sure it does (using a,b,c).
433 // We then simply redo our remove call, and the second time (regardless of
434 // whether we're in case 1 or 2), we'll have enough items and can guarantee
435 // that we hit case A.
436 func (n *node[T]) growChildAndRemove(i int, item T, minItems int, typ toRemove) (T, bool) {
437 if i > 0 && len(n.children[i-1].items) > minItems {
438 // Steal from left child
439 child := n.mutableChild(i)
440 stealFrom := n.mutableChild(i - 1)
441 stolenItem := stealFrom.items.pop()
442 child.items.insertAt(0, n.items[i-1])
443 n.items[i-1] = stolenItem
444 if len(stealFrom.children) > 0 {
445 child.children.insertAt(0, stealFrom.children.pop())
446 }
447 } else if i < len(n.items) && len(n.children[i+1].items) > minItems {
448 // steal from right child
449 child := n.mutableChild(i)
450 stealFrom := n.mutableChild(i + 1)
451 stolenItem := stealFrom.items.removeAt(0)
452 child.items = append(child.items, n.items[i])
453 n.items[i] = stolenItem
454 if len(stealFrom.children) > 0 {
455 child.children = append(child.children, stealFrom.children.removeAt(0))
456 }
457 } else {
458 if i >= len(n.items) {
459 i--
460 }
461 child := n.mutableChild(i)
462 // merge with right child
463 mergeItem := n.items.removeAt(i)
464 mergeChild := n.children.removeAt(i + 1)
465 child.items = append(child.items, mergeItem)
466 child.items = append(child.items, mergeChild.items...)
467 child.children = append(child.children, mergeChild.children...)
468 n.cow.freeNode(mergeChild)
469 }
470 return n.remove(item, minItems, typ)
471 }
472
473 type direction int
474
475 const (
476 descend = direction(-1)
477 ascend = direction(+1)
478 )
479
480 type optionalItem[T any] struct {
481 item T
482 valid bool
483 }
484
485 func optional[T any](item T) optionalItem[T] {
486 return optionalItem[T]{item: item, valid: true}
487 }
488 func empty[T any]() optionalItem[T] {
489 return optionalItem[T]{}
490 }
491
492 // iterate provides a simple method for iterating over elements in the tree.
493 //
494 // When ascending, the 'start' should be less than 'stop' and when descending,
495 // the 'start' should be greater than 'stop'. Setting 'includeStart' to true
496 // will force the iterator to include the first item when it equals 'start',
497 // thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a
498 // "greaterThan" or "lessThan" queries.
499 func (n *node[T]) iterate(dir direction, start, stop optionalItem[T], includeStart bool, hit bool, iter ItemIteratorG[T]) (bool, bool) {
500 var ok, found bool
501 var index int
502 switch dir {
503 case ascend:
504 if start.valid {
505 index, _ = n.items.find(start.item, n.cow.less)
506 }
507 for i := index; i < len(n.items); i++ {
508 if len(n.children) > 0 {
509 if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok {
510 return hit, false
511 }
512 }
513 if !includeStart && !hit && start.valid && !n.cow.less(start.item, n.items[i]) {
514 hit = true
515 continue
516 }
517 hit = true
518 if stop.valid && !n.cow.less(n.items[i], stop.item) {
519 return hit, false
520 }
521 if !iter(n.items[i]) {
522 return hit, false
523 }
524 }
525 if len(n.children) > 0 {
526 if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
527 return hit, false
528 }
529 }
530 case descend:
531 if start.valid {
532 index, found = n.items.find(start.item, n.cow.less)
533 if !found {
534 index = index - 1
535 }
536 } else {
537 index = len(n.items) - 1
538 }
539 for i := index; i >= 0; i-- {
540 if start.valid && !n.cow.less(n.items[i], start.item) {
541 if !includeStart || hit || n.cow.less(start.item, n.items[i]) {
542 continue
543 }
544 }
545 if len(n.children) > 0 {
546 if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter); !ok {
547 return hit, false
548 }
549 }
550 if stop.valid && !n.cow.less(stop.item, n.items[i]) {
551 return hit, false // continue
552 }
553 hit = true
554 if !iter(n.items[i]) {
555 return hit, false
556 }
557 }
558 if len(n.children) > 0 {
559 if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter); !ok {
560 return hit, false
561 }
562 }
563 }
564 return hit, true
565 }
566
567 // print is used for testing/debugging purposes.
568 func (n *node[T]) print(w io.Writer, level int) {
569 fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items)
570 for _, c := range n.children {
571 c.print(w, level+1)
572 }
573 }
574
575 // BTreeG is a generic implementation of a B-Tree.
576 //
577 // BTreeG stores items of type T in an ordered structure, allowing easy insertion,
578 // removal, and iteration.
579 //
580 // Write operations are not safe for concurrent mutation by multiple
581 // goroutines, but Read operations are.
582 type BTreeG[T any] struct {
583 degree int
584 length int
585 root *node[T]
586 cow *copyOnWriteContext[T]
587 }
588
589 // LessFunc[T] determines how to order a type 'T'. It should implement a strict
590 // ordering, and should return true if within that ordering, 'a' < 'b'.
591 type LessFunc[T any] func(a, b T) bool
592
593 // copyOnWriteContext pointers determine node ownership... a tree with a write
594 // context equivalent to a node's write context is allowed to modify that node.
595 // A tree whose write context does not match a node's is not allowed to modify
596 // it, and must create a new, writable copy (IE: it's a Clone).
597 //
598 // When doing any write operation, we maintain the invariant that the current
599 // node's context is equal to the context of the tree that requested the write.
600 // We do this by, before we descend into any node, creating a copy with the
601 // correct context if the contexts don't match.
602 //
603 // Since the node we're currently visiting on any write has the requesting
604 // tree's context, that node is modifiable in place. Children of that node may
605 // not share context, but before we descend into them, we'll make a mutable
606 // copy.
607 type copyOnWriteContext[T any] struct {
608 freelist *FreeListG[T]
609 less LessFunc[T]
610 }
611
612 // Clone clones the btree, lazily. Clone should not be called concurrently,
613 // but the original tree (t) and the new tree (t2) can be used concurrently
614 // once the Clone call completes.
615 //
616 // The internal tree structure of b is marked read-only and shared between t and
617 // t2. Writes to both t and t2 use copy-on-write logic, creating new nodes
618 // whenever one of b's original nodes would have been modified. Read operations
619 // should have no performance degredation. Write operations for both t and t2
620 // will initially experience minor slow-downs caused by additional allocs and
621 // copies due to the aforementioned copy-on-write logic, but should converge to
622 // the original performance characteristics of the original tree.
623 func (t *BTreeG[T]) Clone() (t2 *BTreeG[T]) {
624 // Create two entirely new copy-on-write contexts.
625 // This operation effectively creates three trees:
626 // the original, shared nodes (old b.cow)
627 // the new b.cow nodes
628 // the new out.cow nodes
629 cow1, cow2 := *t.cow, *t.cow
630 out := *t
631 t.cow = &cow1
632 out.cow = &cow2
633 return &out
634 }
635
636 // maxItems returns the max number of items to allow per node.
637 func (t *BTreeG[T]) maxItems() int {
638 return t.degree*2 - 1
639 }
640
641 // minItems returns the min number of items to allow per node (ignored for the
642 // root node).
643 func (t *BTreeG[T]) minItems() int {
644 return t.degree - 1
645 }
646
647 func (c *copyOnWriteContext[T]) newNode() (n *node[T]) {
648 n = c.freelist.newNode()
649 n.cow = c
650 return
651 }
652
653 type freeType int
654
655 const (
656 ftFreelistFull freeType = iota // node was freed (available for GC, not stored in freelist)
657 ftStored // node was stored in the freelist for later use
658 ftNotOwned // node was ignored by COW, since it's owned by another one
659 )
660
661 // freeNode frees a node within a given COW context, if it's owned by that
662 // context. It returns what happened to the node (see freeType const
663 // documentation).
664 func (c *copyOnWriteContext[T]) freeNode(n *node[T]) freeType {
665 if n.cow == c {
666 // clear to allow GC
667 n.items.truncate(0)
668 n.children.truncate(0)
669 n.cow = nil
670 if c.freelist.freeNode(n) {
671 return ftStored
672 } else {
673 return ftFreelistFull
674 }
675 } else {
676 return ftNotOwned
677 }
678 }
679
680 // ReplaceOrInsert adds the given item to the tree. If an item in the tree
681 // already equals the given one, it is removed from the tree and returned,
682 // and the second return value is true. Otherwise, (zeroValue, false)
683 //
684 // nil cannot be added to the tree (will panic).
685 func (t *BTreeG[T]) ReplaceOrInsert(item T) (_ T, _ bool) {
686 if t.root == nil {
687 t.root = t.cow.newNode()
688 t.root.items = append(t.root.items, item)
689 t.length++
690 return
691 } else {
692 t.root = t.root.mutableFor(t.cow)
693 if len(t.root.items) >= t.maxItems() {
694 item2, second := t.root.split(t.maxItems() / 2)
695 oldroot := t.root
696 t.root = t.cow.newNode()
697 t.root.items = append(t.root.items, item2)
698 t.root.children = append(t.root.children, oldroot, second)
699 }
700 }
701 out, outb := t.root.insert(item, t.maxItems())
702 if !outb {
703 t.length++
704 }
705 return out, outb
706 }
707
708 // Delete removes an item equal to the passed in item from the tree, returning
709 // it. If no such item exists, returns (zeroValue, false).
710 func (t *BTreeG[T]) Delete(item T) (T, bool) {
711 return t.deleteItem(item, removeItem)
712 }
713
714 // DeleteMin removes the smallest item in the tree and returns it.
715 // If no such item exists, returns (zeroValue, false).
716 func (t *BTreeG[T]) DeleteMin() (T, bool) {
717 var zero T
718 return t.deleteItem(zero, removeMin)
719 }
720
721 // DeleteMax removes the largest item in the tree and returns it.
722 // If no such item exists, returns (zeroValue, false).
723 func (t *BTreeG[T]) DeleteMax() (T, bool) {
724 var zero T
725 return t.deleteItem(zero, removeMax)
726 }
727
728 func (t *BTreeG[T]) deleteItem(item T, typ toRemove) (_ T, _ bool) {
729 if t.root == nil || len(t.root.items) == 0 {
730 return
731 }
732 t.root = t.root.mutableFor(t.cow)
733 out, outb := t.root.remove(item, t.minItems(), typ)
734 if len(t.root.items) == 0 && len(t.root.children) > 0 {
735 oldroot := t.root
736 t.root = t.root.children[0]
737 t.cow.freeNode(oldroot)
738 }
739 if outb {
740 t.length--
741 }
742 return out, outb
743 }
744
745 // AscendRange calls the iterator for every value in the tree within the range
746 // [greaterOrEqual, lessThan), until iterator returns false.
747 func (t *BTreeG[T]) AscendRange(greaterOrEqual, lessThan T, iterator ItemIteratorG[T]) {
748 if t.root == nil {
749 return
750 }
751 t.root.iterate(ascend, optional[T](greaterOrEqual), optional[T](lessThan), true, false, iterator)
752 }
753
754 // AscendLessThan calls the iterator for every value in the tree within the range
755 // [first, pivot), until iterator returns false.
756 func (t *BTreeG[T]) AscendLessThan(pivot T, iterator ItemIteratorG[T]) {
757 if t.root == nil {
758 return
759 }
760 t.root.iterate(ascend, empty[T](), optional(pivot), false, false, iterator)
761 }
762
763 // AscendGreaterOrEqual calls the iterator for every value in the tree within
764 // the range [pivot, last], until iterator returns false.
765 func (t *BTreeG[T]) AscendGreaterOrEqual(pivot T, iterator ItemIteratorG[T]) {
766 if t.root == nil {
767 return
768 }
769 t.root.iterate(ascend, optional[T](pivot), empty[T](), true, false, iterator)
770 }
771
772 // Ascend calls the iterator for every value in the tree within the range
773 // [first, last], until iterator returns false.
774 func (t *BTreeG[T]) Ascend(iterator ItemIteratorG[T]) {
775 if t.root == nil {
776 return
777 }
778 t.root.iterate(ascend, empty[T](), empty[T](), false, false, iterator)
779 }
780
781 // DescendRange calls the iterator for every value in the tree within the range
782 // [lessOrEqual, greaterThan), until iterator returns false.
783 func (t *BTreeG[T]) DescendRange(lessOrEqual, greaterThan T, iterator ItemIteratorG[T]) {
784 if t.root == nil {
785 return
786 }
787 t.root.iterate(descend, optional[T](lessOrEqual), optional[T](greaterThan), true, false, iterator)
788 }
789
790 // DescendLessOrEqual calls the iterator for every value in the tree within the range
791 // [pivot, first], until iterator returns false.
792 func (t *BTreeG[T]) DescendLessOrEqual(pivot T, iterator ItemIteratorG[T]) {
793 if t.root == nil {
794 return
795 }
796 t.root.iterate(descend, optional[T](pivot), empty[T](), true, false, iterator)
797 }
798
799 // DescendGreaterThan calls the iterator for every value in the tree within
800 // the range [last, pivot), until iterator returns false.
801 func (t *BTreeG[T]) DescendGreaterThan(pivot T, iterator ItemIteratorG[T]) {
802 if t.root == nil {
803 return
804 }
805 t.root.iterate(descend, empty[T](), optional[T](pivot), false, false, iterator)
806 }
807
808 // Descend calls the iterator for every value in the tree within the range
809 // [last, first], until iterator returns false.
810 func (t *BTreeG[T]) Descend(iterator ItemIteratorG[T]) {
811 if t.root == nil {
812 return
813 }
814 t.root.iterate(descend, empty[T](), empty[T](), false, false, iterator)
815 }
816
817 // Get looks for the key item in the tree, returning it. It returns
818 // (zeroValue, false) if unable to find that item.
819 func (t *BTreeG[T]) Get(key T) (_ T, _ bool) {
820 if t.root == nil {
821 return
822 }
823 return t.root.get(key)
824 }
825
826 // Min returns the smallest item in the tree, or (zeroValue, false) if the tree is empty.
827 func (t *BTreeG[T]) Min() (_ T, _ bool) {
828 return min(t.root)
829 }
830
831 // Max returns the largest item in the tree, or (zeroValue, false) if the tree is empty.
832 func (t *BTreeG[T]) Max() (_ T, _ bool) {
833 return max(t.root)
834 }
835
836 // Has returns true if the given key is in the tree.
837 func (t *BTreeG[T]) Has(key T) bool {
838 _, ok := t.Get(key)
839 return ok
840 }
841
842 // Len returns the number of items currently in the tree.
843 func (t *BTreeG[T]) Len() int {
844 return t.length
845 }
846
847 // Clear removes all items from the btree. If addNodesToFreelist is true,
848 // t's nodes are added to its freelist as part of this call, until the freelist
849 // is full. Otherwise, the root node is simply dereferenced and the subtree
850 // left to Go's normal GC processes.
851 //
852 // This can be much faster
853 // than calling Delete on all elements, because that requires finding/removing
854 // each element in the tree and updating the tree accordingly. It also is
855 // somewhat faster than creating a new tree to replace the old one, because
856 // nodes from the old tree are reclaimed into the freelist for use by the new
857 // one, instead of being lost to the garbage collector.
858 //
859 // This call takes:
860 // O(1): when addNodesToFreelist is false, this is a single operation.
861 // O(1): when the freelist is already full, it breaks out immediately
862 // O(freelist size): when the freelist is empty and the nodes are all owned
863 // by this tree, nodes are added to the freelist until full.
864 // O(tree size): when all nodes are owned by another tree, all nodes are
865 // iterated over looking for nodes to add to the freelist, and due to
866 // ownership, none are.
867 func (t *BTreeG[T]) Clear(addNodesToFreelist bool) {
868 if t.root != nil && addNodesToFreelist {
869 t.root.reset(t.cow)
870 }
871 t.root, t.length = nil, 0
872 }
873
874 // reset returns a subtree to the freelist. It breaks out immediately if the
875 // freelist is full, since the only benefit of iterating is to fill that
876 // freelist up. Returns true if parent reset call should continue.
877 func (n *node[T]) reset(c *copyOnWriteContext[T]) bool {
878 for _, child := range n.children {
879 if !child.reset(c) {
880 return false
881 }
882 }
883 return c.freeNode(n) != ftFreelistFull
884 }
885
886 // Int implements the Item interface for integers.
887 type Int int
888
889 // Less returns true if int(a) < int(b).
890 func (a Int) Less(b Item) bool {
891 return a < b.(Int)
892 }
893
894 // BTree is an implementation of a B-Tree.
895 //
896 // BTree stores Item instances in an ordered structure, allowing easy insertion,
897 // removal, and iteration.
898 //
899 // Write operations are not safe for concurrent mutation by multiple
900 // goroutines, but Read operations are.
901 type BTree BTreeG[Item]
902
903 var itemLess LessFunc[Item] = func(a, b Item) bool {
904 return a.Less(b)
905 }
906
907 // New creates a new B-Tree with the given degree.
908 //
909 // New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items
910 // and 2-4 children).
911 func New(degree int) *BTree {
912 return (*BTree)(NewG[Item](degree, itemLess))
913 }
914
915 // FreeList represents a free list of btree nodes. By default each
916 // BTree has its own FreeList, but multiple BTrees can share the same
917 // FreeList.
918 // Two Btrees using the same freelist are safe for concurrent write access.
919 type FreeList FreeListG[Item]
920
921 // NewFreeList creates a new free list.
922 // size is the maximum size of the returned free list.
923 func NewFreeList(size int) *FreeList {
924 return (*FreeList)(NewFreeListG[Item](size))
925 }
926
927 // NewWithFreeList creates a new B-Tree that uses the given node free list.
928 func NewWithFreeList(degree int, f *FreeList) *BTree {
929 return (*BTree)(NewWithFreeListG[Item](degree, itemLess, (*FreeListG[Item])(f)))
930 }
931
932 // ItemIterator allows callers of Ascend* to iterate in-order over portions of
933 // the tree. When this function returns false, iteration will stop and the
934 // associated Ascend* function will immediately return.
935 type ItemIterator ItemIteratorG[Item]
936
937 // Clone clones the btree, lazily. Clone should not be called concurrently,
938 // but the original tree (t) and the new tree (t2) can be used concurrently
939 // once the Clone call completes.
940 //
941 // The internal tree structure of b is marked read-only and shared between t and
942 // t2. Writes to both t and t2 use copy-on-write logic, creating new nodes
943 // whenever one of b's original nodes would have been modified. Read operations
944 // should have no performance degredation. Write operations for both t and t2
945 // will initially experience minor slow-downs caused by additional allocs and
946 // copies due to the aforementioned copy-on-write logic, but should converge to
947 // the original performance characteristics of the original tree.
948 func (t *BTree) Clone() (t2 *BTree) {
949 return (*BTree)((*BTreeG[Item])(t).Clone())
950 }
951
952 // Delete removes an item equal to the passed in item from the tree, returning
953 // it. If no such item exists, returns nil.
954 func (t *BTree) Delete(item Item) Item {
955 i, _ := (*BTreeG[Item])(t).Delete(item)
956 return i
957 }
958
959 // DeleteMax removes the largest item in the tree and returns it.
960 // If no such item exists, returns nil.
961 func (t *BTree) DeleteMax() Item {
962 i, _ := (*BTreeG[Item])(t).DeleteMax()
963 return i
964 }
965
966 // DeleteMin removes the smallest item in the tree and returns it.
967 // If no such item exists, returns nil.
968 func (t *BTree) DeleteMin() Item {
969 i, _ := (*BTreeG[Item])(t).DeleteMin()
970 return i
971 }
972
973 // Get looks for the key item in the tree, returning it. It returns nil if
974 // unable to find that item.
975 func (t *BTree) Get(key Item) Item {
976 i, _ := (*BTreeG[Item])(t).Get(key)
977 return i
978 }
979
980 // Max returns the largest item in the tree, or nil if the tree is empty.
981 func (t *BTree) Max() Item {
982 i, _ := (*BTreeG[Item])(t).Max()
983 return i
984 }
985
986 // Min returns the smallest item in the tree, or nil if the tree is empty.
987 func (t *BTree) Min() Item {
988 i, _ := (*BTreeG[Item])(t).Min()
989 return i
990 }
991
992 // Has returns true if the given key is in the tree.
993 func (t *BTree) Has(key Item) bool {
994 return (*BTreeG[Item])(t).Has(key)
995 }
996
997 // ReplaceOrInsert adds the given item to the tree. If an item in the tree
998 // already equals the given one, it is removed from the tree and returned.
999 // Otherwise, nil is returned.
1000 //
1001 // nil cannot be added to the tree (will panic).
1002 func (t *BTree) ReplaceOrInsert(item Item) Item {
1003 i, _ := (*BTreeG[Item])(t).ReplaceOrInsert(item)
1004 return i
1005 }
1006
1007 // AscendRange calls the iterator for every value in the tree within the range
1008 // [greaterOrEqual, lessThan), until iterator returns false.
1009 func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) {
1010 (*BTreeG[Item])(t).AscendRange(greaterOrEqual, lessThan, (ItemIteratorG[Item])(iterator))
1011 }
1012
1013 // AscendLessThan calls the iterator for every value in the tree within the range
1014 // [first, pivot), until iterator returns false.
1015 func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) {
1016 (*BTreeG[Item])(t).AscendLessThan(pivot, (ItemIteratorG[Item])(iterator))
1017 }
1018
1019 // AscendGreaterOrEqual calls the iterator for every value in the tree within
1020 // the range [pivot, last], until iterator returns false.
1021 func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) {
1022 (*BTreeG[Item])(t).AscendGreaterOrEqual(pivot, (ItemIteratorG[Item])(iterator))
1023 }
1024
1025 // Ascend calls the iterator for every value in the tree within the range
1026 // [first, last], until iterator returns false.
1027 func (t *BTree) Ascend(iterator ItemIterator) {
1028 (*BTreeG[Item])(t).Ascend((ItemIteratorG[Item])(iterator))
1029 }
1030
1031 // DescendRange calls the iterator for every value in the tree within the range
1032 // [lessOrEqual, greaterThan), until iterator returns false.
1033 func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) {
1034 (*BTreeG[Item])(t).DescendRange(lessOrEqual, greaterThan, (ItemIteratorG[Item])(iterator))
1035 }
1036
1037 // DescendLessOrEqual calls the iterator for every value in the tree within the range
1038 // [pivot, first], until iterator returns false.
1039 func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) {
1040 (*BTreeG[Item])(t).DescendLessOrEqual(pivot, (ItemIteratorG[Item])(iterator))
1041 }
1042
1043 // DescendGreaterThan calls the iterator for every value in the tree within
1044 // the range [last, pivot), until iterator returns false.
1045 func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) {
1046 (*BTreeG[Item])(t).DescendGreaterThan(pivot, (ItemIteratorG[Item])(iterator))
1047 }
1048
1049 // Descend calls the iterator for every value in the tree within the range
1050 // [last, first], until iterator returns false.
1051 func (t *BTree) Descend(iterator ItemIterator) {
1052 (*BTreeG[Item])(t).Descend((ItemIteratorG[Item])(iterator))
1053 }
1054
1055 // Len returns the number of items currently in the tree.
1056 func (t *BTree) Len() int {
1057 return (*BTreeG[Item])(t).Len()
1058 }
1059
1060 // Clear removes all items from the btree. If addNodesToFreelist is true,
1061 // t's nodes are added to its freelist as part of this call, until the freelist
1062 // is full. Otherwise, the root node is simply dereferenced and the subtree
1063 // left to Go's normal GC processes.
1064 //
1065 // This can be much faster
1066 // than calling Delete on all elements, because that requires finding/removing
1067 // each element in the tree and updating the tree accordingly. It also is
1068 // somewhat faster than creating a new tree to replace the old one, because
1069 // nodes from the old tree are reclaimed into the freelist for use by the new
1070 // one, instead of being lost to the garbage collector.
1071 //
1072 // This call takes:
1073 // O(1): when addNodesToFreelist is false, this is a single operation.
1074 // O(1): when the freelist is already full, it breaks out immediately
1075 // O(freelist size): when the freelist is empty and the nodes are all owned
1076 // by this tree, nodes are added to the freelist until full.
1077 // O(tree size): when all nodes are owned by another tree, all nodes are
1078 // iterated over looking for nodes to add to the freelist, and due to
1079 // ownership, none are.
1080 func (t *BTree) Clear(addNodesToFreelist bool) {
1081 (*BTreeG[Item])(t).Clear(addNodesToFreelist)
1082 }
0 // Copyright 2014-2022 Google Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 //go:build go1.18
15 // +build go1.18
16
17 package btree
18
19 import (
20 "fmt"
21 "math/rand"
22 "reflect"
23 "sort"
24 "sync"
25 "testing"
26 )
27
28 func intRange(s int, reverse bool) []int {
29 out := make([]int, s)
30 for i := 0; i < s; i++ {
31 v := i
32 if reverse {
33 v = s - i - 1
34 }
35 out[i] = v
36 }
37 return out
38 }
39
40 func intAll(t *BTreeG[int]) (out []int) {
41 t.Ascend(func(a int) bool {
42 out = append(out, a)
43 return true
44 })
45 return
46 }
47
48 func intAllRev(t *BTreeG[int]) (out []int) {
49 t.Descend(func(a int) bool {
50 out = append(out, a)
51 return true
52 })
53 return
54 }
55
56 func TestBTreeG(t *testing.T) {
57 tr := NewOrderedG[int](*btreeDegree)
58 const treeSize = 10000
59 for i := 0; i < 10; i++ {
60 if min, ok := tr.Min(); ok || min != 0 {
61 t.Fatalf("empty min, got %+v", min)
62 }
63 if max, ok := tr.Max(); ok || max != 0 {
64 t.Fatalf("empty max, got %+v", max)
65 }
66 for _, item := range rand.Perm(treeSize) {
67 if x, ok := tr.ReplaceOrInsert(item); ok || x != 0 {
68 t.Fatal("insert found item", item)
69 }
70 }
71 for _, item := range rand.Perm(treeSize) {
72 if x, ok := tr.ReplaceOrInsert(item); !ok || x != item {
73 t.Fatal("insert didn't find item", item)
74 }
75 }
76 want := 0
77 if min, ok := tr.Min(); !ok || min != want {
78 t.Fatalf("min: ok %v want %+v, got %+v", ok, want, min)
79 }
80 want = treeSize - 1
81 if max, ok := tr.Max(); !ok || max != want {
82 t.Fatalf("max: ok %v want %+v, got %+v", ok, want, max)
83 }
84 got := intAll(tr)
85 wantRange := intRange(treeSize, false)
86 if !reflect.DeepEqual(got, wantRange) {
87 t.Fatalf("mismatch:\n got: %v\nwant: %v", got, wantRange)
88 }
89
90 gotrev := intAllRev(tr)
91 wantrev := intRange(treeSize, true)
92 if !reflect.DeepEqual(gotrev, wantrev) {
93 t.Fatalf("mismatch:\n got: %v\nwant: %v", gotrev, wantrev)
94 }
95
96 for _, item := range rand.Perm(treeSize) {
97 if x, ok := tr.Delete(item); !ok || x != item {
98 t.Fatalf("didn't find %v", item)
99 }
100 }
101 if got = intAll(tr); len(got) > 0 {
102 t.Fatalf("some left!: %v", got)
103 }
104 if got = intAllRev(tr); len(got) > 0 {
105 t.Fatalf("some left!: %v", got)
106 }
107 }
108 }
109
110 func ExampleBTreeG() {
111 tr := NewOrderedG[int](*btreeDegree)
112 for i := 0; i < 10; i++ {
113 tr.ReplaceOrInsert(i)
114 }
115 fmt.Println("len: ", tr.Len())
116 v, ok := tr.Get(3)
117 fmt.Println("get3: ", v, ok)
118 v, ok = tr.Get(100)
119 fmt.Println("get100: ", v, ok)
120 v, ok = tr.Delete(4)
121 fmt.Println("del4: ", v, ok)
122 v, ok = tr.Delete(100)
123 fmt.Println("del100: ", v, ok)
124 v, ok = tr.ReplaceOrInsert(5)
125 fmt.Println("replace5: ", v, ok)
126 v, ok = tr.ReplaceOrInsert(100)
127 fmt.Println("replace100:", v, ok)
128 v, ok = tr.Min()
129 fmt.Println("min: ", v, ok)
130 v, ok = tr.DeleteMin()
131 fmt.Println("delmin: ", v, ok)
132 v, ok = tr.Max()
133 fmt.Println("max: ", v, ok)
134 v, ok = tr.DeleteMax()
135 fmt.Println("delmax: ", v, ok)
136 fmt.Println("len: ", tr.Len())
137 // Output:
138 // len: 10
139 // get3: 3 true
140 // get100: 0 false
141 // del4: 4 true
142 // del100: 0 false
143 // replace5: 5 true
144 // replace100: 0 false
145 // min: 0 true
146 // delmin: 0 true
147 // max: 100 true
148 // delmax: 100 true
149 // len: 8
150 }
151
152 func TestDeleteMinG(t *testing.T) {
153 tr := NewOrderedG[int](3)
154 for _, v := range rand.Perm(100) {
155 tr.ReplaceOrInsert(v)
156 }
157 var got []int
158 for v, ok := tr.DeleteMin(); ok; v, ok = tr.DeleteMin() {
159 got = append(got, v)
160 }
161 if want := intRange(100, false); !reflect.DeepEqual(got, want) {
162 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
163 }
164 }
165
166 func TestDeleteMaxG(t *testing.T) {
167 tr := NewOrderedG[int](3)
168 for _, v := range rand.Perm(100) {
169 tr.ReplaceOrInsert(v)
170 }
171 var got []int
172 for v, ok := tr.DeleteMax(); ok; v, ok = tr.DeleteMax() {
173 got = append(got, v)
174 }
175 if want := intRange(100, true); !reflect.DeepEqual(got, want) {
176 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
177 }
178 }
179
180 func TestAscendRangeG(t *testing.T) {
181 tr := NewOrderedG[int](2)
182 for _, v := range rand.Perm(100) {
183 tr.ReplaceOrInsert(v)
184 }
185 var got []int
186 tr.AscendRange(40, 60, func(a int) bool {
187 got = append(got, a)
188 return true
189 })
190 if want := intRange(100, false)[40:60]; !reflect.DeepEqual(got, want) {
191 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
192 }
193 got = got[:0]
194 tr.AscendRange(40, 60, func(a int) bool {
195 if a > 50 {
196 return false
197 }
198 got = append(got, a)
199 return true
200 })
201 if want := intRange(100, false)[40:51]; !reflect.DeepEqual(got, want) {
202 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
203 }
204 }
205
206 func TestDescendRangeG(t *testing.T) {
207 tr := NewOrderedG[int](2)
208 for _, v := range rand.Perm(100) {
209 tr.ReplaceOrInsert(v)
210 }
211 var got []int
212 tr.DescendRange(60, 40, func(a int) bool {
213 got = append(got, a)
214 return true
215 })
216 if want := intRange(100, true)[39:59]; !reflect.DeepEqual(got, want) {
217 t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want)
218 }
219 got = got[:0]
220 tr.DescendRange(60, 40, func(a int) bool {
221 if a < 50 {
222 return false
223 }
224 got = append(got, a)
225 return true
226 })
227 if want := intRange(100, true)[39:50]; !reflect.DeepEqual(got, want) {
228 t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want)
229 }
230 }
231
232 func TestAscendLessThanG(t *testing.T) {
233 tr := NewOrderedG[int](*btreeDegree)
234 for _, v := range rand.Perm(100) {
235 tr.ReplaceOrInsert(v)
236 }
237 var got []int
238 tr.AscendLessThan(60, func(a int) bool {
239 got = append(got, a)
240 return true
241 })
242 if want := intRange(100, false)[:60]; !reflect.DeepEqual(got, want) {
243 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
244 }
245 got = got[:0]
246 tr.AscendLessThan(60, func(a int) bool {
247 if a > 50 {
248 return false
249 }
250 got = append(got, a)
251 return true
252 })
253 if want := intRange(100, false)[:51]; !reflect.DeepEqual(got, want) {
254 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
255 }
256 }
257
258 func TestDescendLessOrEqualG(t *testing.T) {
259 tr := NewOrderedG[int](*btreeDegree)
260 for _, v := range rand.Perm(100) {
261 tr.ReplaceOrInsert(v)
262 }
263 var got []int
264 tr.DescendLessOrEqual(40, func(a int) bool {
265 got = append(got, a)
266 return true
267 })
268 if want := intRange(100, true)[59:]; !reflect.DeepEqual(got, want) {
269 t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want)
270 }
271 got = got[:0]
272 tr.DescendLessOrEqual(60, func(a int) bool {
273 if a < 50 {
274 return false
275 }
276 got = append(got, a)
277 return true
278 })
279 if want := intRange(100, true)[39:50]; !reflect.DeepEqual(got, want) {
280 t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want)
281 }
282 }
283
284 func TestAscendGreaterOrEqualG(t *testing.T) {
285 tr := NewOrderedG[int](*btreeDegree)
286 for _, v := range rand.Perm(100) {
287 tr.ReplaceOrInsert(v)
288 }
289 var got []int
290 tr.AscendGreaterOrEqual(40, func(a int) bool {
291 got = append(got, a)
292 return true
293 })
294 if want := intRange(100, false)[40:]; !reflect.DeepEqual(got, want) {
295 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
296 }
297 got = got[:0]
298 tr.AscendGreaterOrEqual(40, func(a int) bool {
299 if a > 50 {
300 return false
301 }
302 got = append(got, a)
303 return true
304 })
305 if want := intRange(100, false)[40:51]; !reflect.DeepEqual(got, want) {
306 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want)
307 }
308 }
309
310 func TestDescendGreaterThanG(t *testing.T) {
311 tr := NewOrderedG[int](*btreeDegree)
312 for _, v := range rand.Perm(100) {
313 tr.ReplaceOrInsert(v)
314 }
315 var got []int
316 tr.DescendGreaterThan(40, func(a int) bool {
317 got = append(got, a)
318 return true
319 })
320 if want := intRange(100, true)[:59]; !reflect.DeepEqual(got, want) {
321 t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want)
322 }
323 got = got[:0]
324 tr.DescendGreaterThan(40, func(a int) bool {
325 if a < 50 {
326 return false
327 }
328 got = append(got, a)
329 return true
330 })
331 if want := intRange(100, true)[:50]; !reflect.DeepEqual(got, want) {
332 t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want)
333 }
334 }
335
336 func BenchmarkInsertG(b *testing.B) {
337 b.StopTimer()
338 insertP := rand.Perm(benchmarkTreeSize)
339 b.StartTimer()
340 i := 0
341 for i < b.N {
342 tr := NewOrderedG[int](*btreeDegree)
343 for _, item := range insertP {
344 tr.ReplaceOrInsert(item)
345 i++
346 if i >= b.N {
347 return
348 }
349 }
350 }
351 }
352
353 func BenchmarkSeekG(b *testing.B) {
354 b.StopTimer()
355 size := 100000
356 insertP := rand.Perm(size)
357 tr := NewOrderedG[int](*btreeDegree)
358 for _, item := range insertP {
359 tr.ReplaceOrInsert(item)
360 }
361 b.StartTimer()
362
363 for i := 0; i < b.N; i++ {
364 tr.AscendGreaterOrEqual(i%size, func(i int) bool { return false })
365 }
366 }
367
368 func BenchmarkDeleteInsertG(b *testing.B) {
369 b.StopTimer()
370 insertP := rand.Perm(benchmarkTreeSize)
371 tr := NewOrderedG[int](*btreeDegree)
372 for _, item := range insertP {
373 tr.ReplaceOrInsert(item)
374 }
375 b.StartTimer()
376 for i := 0; i < b.N; i++ {
377 tr.Delete(insertP[i%benchmarkTreeSize])
378 tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize])
379 }
380 }
381
382 func BenchmarkDeleteInsertCloneOnceG(b *testing.B) {
383 b.StopTimer()
384 insertP := rand.Perm(benchmarkTreeSize)
385 tr := NewOrderedG[int](*btreeDegree)
386 for _, item := range insertP {
387 tr.ReplaceOrInsert(item)
388 }
389 tr = tr.Clone()
390 b.StartTimer()
391 for i := 0; i < b.N; i++ {
392 tr.Delete(insertP[i%benchmarkTreeSize])
393 tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize])
394 }
395 }
396
397 func BenchmarkDeleteInsertCloneEachTimeG(b *testing.B) {
398 b.StopTimer()
399 insertP := rand.Perm(benchmarkTreeSize)
400 tr := NewOrderedG[int](*btreeDegree)
401 for _, item := range insertP {
402 tr.ReplaceOrInsert(item)
403 }
404 b.StartTimer()
405 for i := 0; i < b.N; i++ {
406 tr = tr.Clone()
407 tr.Delete(insertP[i%benchmarkTreeSize])
408 tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize])
409 }
410 }
411
412 func BenchmarkDeleteG(b *testing.B) {
413 b.StopTimer()
414 insertP := rand.Perm(benchmarkTreeSize)
415 removeP := rand.Perm(benchmarkTreeSize)
416 b.StartTimer()
417 i := 0
418 for i < b.N {
419 b.StopTimer()
420 tr := NewOrderedG[int](*btreeDegree)
421 for _, v := range insertP {
422 tr.ReplaceOrInsert(v)
423 }
424 b.StartTimer()
425 for _, item := range removeP {
426 tr.Delete(item)
427 i++
428 if i >= b.N {
429 return
430 }
431 }
432 if tr.Len() > 0 {
433 panic(tr.Len())
434 }
435 }
436 }
437
438 func BenchmarkGetG(b *testing.B) {
439 b.StopTimer()
440 insertP := rand.Perm(benchmarkTreeSize)
441 removeP := rand.Perm(benchmarkTreeSize)
442 b.StartTimer()
443 i := 0
444 for i < b.N {
445 b.StopTimer()
446 tr := NewOrderedG[int](*btreeDegree)
447 for _, v := range insertP {
448 tr.ReplaceOrInsert(v)
449 }
450 b.StartTimer()
451 for _, item := range removeP {
452 tr.Get(item)
453 i++
454 if i >= b.N {
455 return
456 }
457 }
458 }
459 }
460
461 func BenchmarkGetCloneEachTimeG(b *testing.B) {
462 b.StopTimer()
463 insertP := rand.Perm(benchmarkTreeSize)
464 removeP := rand.Perm(benchmarkTreeSize)
465 b.StartTimer()
466 i := 0
467 for i < b.N {
468 b.StopTimer()
469 tr := NewOrderedG[int](*btreeDegree)
470 for _, v := range insertP {
471 tr.ReplaceOrInsert(v)
472 }
473 b.StartTimer()
474 for _, item := range removeP {
475 tr = tr.Clone()
476 tr.Get(item)
477 i++
478 if i >= b.N {
479 return
480 }
481 }
482 }
483 }
484
485 func BenchmarkAscendG(b *testing.B) {
486 arr := rand.Perm(benchmarkTreeSize)
487 tr := NewOrderedG[int](*btreeDegree)
488 for _, v := range arr {
489 tr.ReplaceOrInsert(v)
490 }
491 sort.Ints(arr)
492 b.ResetTimer()
493 for i := 0; i < b.N; i++ {
494 j := 0
495 tr.Ascend(func(item int) bool {
496 if item != arr[j] {
497 b.Fatalf("mismatch: expected: %v, got %v", arr[j], item)
498 }
499 j++
500 return true
501 })
502 }
503 }
504
505 func BenchmarkDescendG(b *testing.B) {
506 arr := rand.Perm(benchmarkTreeSize)
507 tr := NewOrderedG[int](*btreeDegree)
508 for _, v := range arr {
509 tr.ReplaceOrInsert(v)
510 }
511 sort.Ints(arr)
512 b.ResetTimer()
513 for i := 0; i < b.N; i++ {
514 j := len(arr) - 1
515 tr.Descend(func(item int) bool {
516 if item != arr[j] {
517 b.Fatalf("mismatch: expected: %v, got %v", arr[j], item)
518 }
519 j--
520 return true
521 })
522 }
523 }
524
525 func BenchmarkAscendRangeG(b *testing.B) {
526 arr := rand.Perm(benchmarkTreeSize)
527 tr := NewOrderedG[int](*btreeDegree)
528 for _, v := range arr {
529 tr.ReplaceOrInsert(v)
530 }
531 sort.Ints(arr)
532 b.ResetTimer()
533 for i := 0; i < b.N; i++ {
534 j := 100
535 tr.AscendRange(100, arr[len(arr)-100], func(item int) bool {
536 if item != arr[j] {
537 b.Fatalf("mismatch: expected: %v, got %v", arr[j], item)
538 }
539 j++
540 return true
541 })
542 if j != len(arr)-100 {
543 b.Fatalf("expected: %v, got %v", len(arr)-100, j)
544 }
545 }
546 }
547
548 func BenchmarkDescendRangeG(b *testing.B) {
549 arr := rand.Perm(benchmarkTreeSize)
550 tr := NewOrderedG[int](*btreeDegree)
551 for _, v := range arr {
552 tr.ReplaceOrInsert(v)
553 }
554 sort.Ints(arr)
555 b.ResetTimer()
556 for i := 0; i < b.N; i++ {
557 j := len(arr) - 100
558 tr.DescendRange(arr[len(arr)-100], 100, func(item int) bool {
559 if item != arr[j] {
560 b.Fatalf("mismatch: expected: %v, got %v", arr[j], item)
561 }
562 j--
563 return true
564 })
565 if j != 100 {
566 b.Fatalf("expected: %v, got %v", len(arr)-100, j)
567 }
568 }
569 }
570
571 func BenchmarkAscendGreaterOrEqualG(b *testing.B) {
572 arr := rand.Perm(benchmarkTreeSize)
573 tr := NewOrderedG[int](*btreeDegree)
574 for _, v := range arr {
575 tr.ReplaceOrInsert(v)
576 }
577 sort.Ints(arr)
578 b.ResetTimer()
579 for i := 0; i < b.N; i++ {
580 j := 100
581 k := 0
582 tr.AscendGreaterOrEqual(100, func(item int) bool {
583 if item != arr[j] {
584 b.Fatalf("mismatch: expected: %v, got %v", arr[j], item)
585 }
586 j++
587 k++
588 return true
589 })
590 if j != len(arr) {
591 b.Fatalf("expected: %v, got %v", len(arr), j)
592 }
593 if k != len(arr)-100 {
594 b.Fatalf("expected: %v, got %v", len(arr)-100, k)
595 }
596 }
597 }
598
599 func BenchmarkDescendLessOrEqualG(b *testing.B) {
600 arr := rand.Perm(benchmarkTreeSize)
601 tr := NewOrderedG[int](*btreeDegree)
602 for _, v := range arr {
603 tr.ReplaceOrInsert(v)
604 }
605 sort.Ints(arr)
606 b.ResetTimer()
607 for i := 0; i < b.N; i++ {
608 j := len(arr) - 100
609 k := len(arr)
610 tr.DescendLessOrEqual(arr[len(arr)-100], func(item int) bool {
611 if item != arr[j] {
612 b.Fatalf("mismatch: expected: %v, got %v", arr[j], item)
613 }
614 j--
615 k--
616 return true
617 })
618 if j != -1 {
619 b.Fatalf("expected: %v, got %v", -1, j)
620 }
621 if k != 99 {
622 b.Fatalf("expected: %v, got %v", 99, k)
623 }
624 }
625 }
626
627 func cloneTestG(t *testing.T, b *BTreeG[int], start int, p []int, wg *sync.WaitGroup, trees *[]*BTreeG[int], lock *sync.Mutex) {
628 t.Logf("Starting new clone at %v", start)
629 lock.Lock()
630 *trees = append(*trees, b)
631 lock.Unlock()
632 for i := start; i < cloneTestSize; i++ {
633 b.ReplaceOrInsert(p[i])
634 if i%(cloneTestSize/5) == 0 {
635 wg.Add(1)
636 go cloneTestG(t, b.Clone(), i+1, p, wg, trees, lock)
637 }
638 }
639 wg.Done()
640 }
641
642 func TestCloneConcurrentOperationsG(t *testing.T) {
643 b := NewOrderedG[int](*btreeDegree)
644 trees := []*BTreeG[int]{}
645 p := rand.Perm(cloneTestSize)
646 var wg sync.WaitGroup
647 wg.Add(1)
648 go cloneTestG(t, b, 0, p, &wg, &trees, &sync.Mutex{})
649 wg.Wait()
650 want := intRange(cloneTestSize, false)
651 t.Logf("Starting equality checks on %d trees", len(trees))
652 for i, tree := range trees {
653 if !reflect.DeepEqual(want, intAll(tree)) {
654 t.Errorf("tree %v mismatch", i)
655 }
656 }
657 t.Log("Removing half from first half")
658 toRemove := intRange(cloneTestSize, false)[cloneTestSize/2:]
659 for i := 0; i < len(trees)/2; i++ {
660 tree := trees[i]
661 wg.Add(1)
662 go func() {
663 for _, item := range toRemove {
664 tree.Delete(item)
665 }
666 wg.Done()
667 }()
668 }
669 wg.Wait()
670 t.Log("Checking all values again")
671 for i, tree := range trees {
672 var wantpart []int
673 if i < len(trees)/2 {
674 wantpart = want[:cloneTestSize/2]
675 } else {
676 wantpart = want
677 }
678 if got := intAll(tree); !reflect.DeepEqual(wantpart, got) {
679 t.Errorf("tree %v mismatch, want %v got %v", i, len(want), len(got))
680 }
681 }
682 }
683
684 func BenchmarkDeleteAndRestoreG(b *testing.B) {
685 items := rand.Perm(16392)
686 b.ResetTimer()
687 b.Run(`CopyBigFreeList`, func(b *testing.B) {
688 fl := NewFreeListG[int](16392)
689 tr := NewWithFreeListG[int](*btreeDegree, Less[int](), fl)
690 for _, v := range items {
691 tr.ReplaceOrInsert(v)
692 }
693 b.ReportAllocs()
694 b.ResetTimer()
695 for i := 0; i < b.N; i++ {
696 dels := make([]int, 0, tr.Len())
697 tr.Ascend(func(b int) bool {
698 dels = append(dels, b)
699 return true
700 })
701 for _, del := range dels {
702 tr.Delete(del)
703 }
704 // tr is now empty, we make a new empty copy of it.
705 tr = NewWithFreeListG[int](*btreeDegree, Less[int](), fl)
706 for _, v := range items {
707 tr.ReplaceOrInsert(v)
708 }
709 }
710 })
711 b.Run(`Copy`, func(b *testing.B) {
712 tr := NewOrderedG[int](*btreeDegree)
713 for _, v := range items {
714 tr.ReplaceOrInsert(v)
715 }
716 b.ReportAllocs()
717 b.ResetTimer()
718 for i := 0; i < b.N; i++ {
719 dels := make([]int, 0, tr.Len())
720 tr.Ascend(func(b int) bool {
721 dels = append(dels, b)
722 return true
723 })
724 for _, del := range dels {
725 tr.Delete(del)
726 }
727 // tr is now empty, we make a new empty copy of it.
728 tr = NewOrderedG[int](*btreeDegree)
729 for _, v := range items {
730 tr.ReplaceOrInsert(v)
731 }
732 }
733 })
734 b.Run(`ClearBigFreelist`, func(b *testing.B) {
735 fl := NewFreeListG[int](16392)
736 tr := NewWithFreeListG[int](*btreeDegree, Less[int](), fl)
737 for _, v := range items {
738 tr.ReplaceOrInsert(v)
739 }
740 b.ReportAllocs()
741 b.ResetTimer()
742 for i := 0; i < b.N; i++ {
743 tr.Clear(true)
744 for _, v := range items {
745 tr.ReplaceOrInsert(v)
746 }
747 }
748 })
749 b.Run(`Clear`, func(b *testing.B) {
750 tr := NewOrderedG[int](*btreeDegree)
751 for _, v := range items {
752 tr.ReplaceOrInsert(v)
753 }
754 b.ReportAllocs()
755 b.ResetTimer()
756 for i := 0; i < b.N; i++ {
757 tr.Clear(true)
758 for _, v := range items {
759 tr.ReplaceOrInsert(v)
760 }
761 }
762 })
763 }
8787 for _, item := range perm(treeSize) {
8888 if x := tr.ReplaceOrInsert(item); x != nil {
8989 t.Fatal("insert found item", item)
90 }
91 }
92 for _, item := range perm(treeSize) {
93 if !tr.Has(item) {
94 t.Fatal("has did not find item", item)
9095 }
9196 }
9297 for _, item := range perm(treeSize) {
647652
648653 const cloneTestSize = 10000
649654
650 func cloneTest(t *testing.T, b *BTree, start int, p []Item, wg *sync.WaitGroup, trees *[]*BTree) {
655 func cloneTest(t *testing.T, b *BTree, start int, p []Item, wg *sync.WaitGroup, trees *[]*BTree, lock *sync.Mutex) {
651656 t.Logf("Starting new clone at %v", start)
657 lock.Lock()
652658 *trees = append(*trees, b)
659 lock.Unlock()
653660 for i := start; i < cloneTestSize; i++ {
654661 b.ReplaceOrInsert(p[i])
655662 if i%(cloneTestSize/5) == 0 {
656663 wg.Add(1)
657 go cloneTest(t, b.Clone(), i+1, p, wg, trees)
664 go cloneTest(t, b.Clone(), i+1, p, wg, trees, lock)
658665 }
659666 }
660667 wg.Done()
666673 p := perm(cloneTestSize)
667674 var wg sync.WaitGroup
668675 wg.Add(1)
669 go cloneTest(t, b, 0, p, &wg, &trees)
676 go cloneTest(t, b, 0, p, &wg, &trees, &sync.Mutex{})
670677 wg.Wait()
671678 want := rang(cloneTestSize)
672679 t.Logf("Starting equality checks on %d trees", len(trees))
0 // Copyright 2014 Google Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 module github.com/google/btree
15
16 go 1.18