|
16 | 16 | // See the License for the specific language governing permissions and |
17 | 17 | // limitations under the License. |
18 | 18 |
|
19 | | -// In Go 1.18 and beyond, a BTreeG generic is created, and BTree is a specific |
20 | | -// instantiation of that generic for the Item interface, with a backwards- |
21 | | -// compatible API. Before go1.18, generics are not supported, |
22 | | -// and BTree is just an implementation based around the Item interface. |
23 | | - |
24 | 19 | // Package btree implements in-memory B-Trees of arbitrary degree. |
25 | 20 | // |
26 | 21 | // btree implements an in-memory B-Tree for use as an ordered data structure. |
|
57 | 52 | // Its functions, therefore, exactly mirror those of |
58 | 53 | // llrb.LLRB where possible. Unlike gollrb, though, we currently don't |
59 | 54 | // support storing multiple equivalent values. |
60 | | -// |
61 | | -// There are two implementations; those suffixed with 'G' are generics, usable |
62 | | -// for any type, and require a passed-in "less" function to define their ordering. |
63 | | -// Those without this prefix are specific to the 'Item' interface, and use |
64 | | -// its 'Less' function for ordering. |
65 | 55 | package btree |
66 | 56 |
|
67 | 57 | import ( |
68 | 58 | "sort" |
69 | 59 | "sync" |
70 | 60 | ) |
71 | 61 |
|
72 | | -// Item represents a single object in the tree. |
73 | | -type Item interface { |
74 | | - // Less tests whether the current item is less than the given argument. |
75 | | - // |
76 | | - // This must provide a strict weak ordering. |
77 | | - // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only |
78 | | - // hold one of either a or b in the tree). |
79 | | - Less(than Item) bool |
80 | | -} |
81 | | - |
82 | 62 | // DefaultFreeListSize is the default capacity of a BTree node free list. |
83 | 63 | const DefaultFreeListSize = 32 |
84 | 64 |
|
@@ -878,202 +858,3 @@ func (n *node[T]) reset(c *copyOnWriteContext[T]) bool { |
878 | 858 | } |
879 | 859 | return c.freeNode(n) != ftFreelistFull |
880 | 860 | } |
881 | | - |
882 | | -// Int implements the Item interface for integers. |
883 | | -type Int int |
884 | | - |
885 | | -// Less returns true if int(a) < int(b). |
886 | | -func (a Int) Less(b Item) bool { |
887 | | - return a < b.(Int) |
888 | | -} |
889 | | - |
890 | | -// BTree is an implementation of a B-Tree. |
891 | | -// |
892 | | -// BTree stores Item instances in an ordered structure, allowing easy insertion, |
893 | | -// removal, and iteration. |
894 | | -// |
895 | | -// Write operations are not safe for concurrent mutation by multiple |
896 | | -// goroutines, but Read operations are. |
897 | | -type BTree BTreeG[Item] |
898 | | - |
899 | | -var itemLess LessFunc[Item] = func(a, b Item) bool { |
900 | | - return a.Less(b) |
901 | | -} |
902 | | - |
903 | | -// New creates a new B-Tree with the given degree. |
904 | | -// |
905 | | -// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items |
906 | | -// and 2-4 children). |
907 | | -func New(degree int) *BTree { |
908 | | - return (*BTree)(NewG[Item](degree, itemLess)) |
909 | | -} |
910 | | - |
911 | | -// FreeList represents a free list of btree nodes. By default each |
912 | | -// BTree has its own FreeList, but multiple BTrees can share the same |
913 | | -// FreeList. |
914 | | -// Two Btrees using the same freelist are safe for concurrent write access. |
915 | | -type FreeList FreeListG[Item] |
916 | | - |
917 | | -// NewFreeList creates a new free list. |
918 | | -// size is the maximum size of the returned free list. |
919 | | -func NewFreeList(size int) *FreeList { |
920 | | - return (*FreeList)(NewFreeListG[Item](size)) |
921 | | -} |
922 | | - |
923 | | -// NewWithFreeList creates a new B-Tree that uses the given node free list. |
924 | | -func NewWithFreeList(degree int, f *FreeList) *BTree { |
925 | | - return (*BTree)(NewWithFreeListG[Item](degree, itemLess, (*FreeListG[Item])(f))) |
926 | | -} |
927 | | - |
928 | | -// ItemIterator allows callers of Ascend* to iterate in-order over portions of |
929 | | -// the tree. When this function returns false, iteration will stop and the |
930 | | -// associated Ascend* function will immediately return. |
931 | | -type ItemIterator ItemIteratorG[Item] |
932 | | - |
933 | | -// Clone clones the btree, lazily. Clone should not be called concurrently, |
934 | | -// but the original tree (t) and the new tree (t2) can be used concurrently |
935 | | -// once the Clone call completes. |
936 | | -// |
937 | | -// The internal tree structure of b is marked read-only and shared between t and |
938 | | -// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes |
939 | | -// whenever one of b's original nodes would have been modified. Read operations |
940 | | -// should have no performance degredation. Write operations for both t and t2 |
941 | | -// will initially experience minor slow-downs caused by additional allocs and |
942 | | -// copies due to the aforementioned copy-on-write logic, but should converge to |
943 | | -// the original performance characteristics of the original tree. |
944 | | -func (t *BTree) Clone() (t2 *BTree) { |
945 | | - return (*BTree)((*BTreeG[Item])(t).Clone()) |
946 | | -} |
947 | | - |
948 | | -// Delete removes an item equal to the passed in item from the tree, returning |
949 | | -// it. If no such item exists, returns nil. |
950 | | -func (t *BTree) Delete(item Item) Item { |
951 | | - i, _ := (*BTreeG[Item])(t).Delete(item) |
952 | | - return i |
953 | | -} |
954 | | - |
955 | | -// DeleteMax removes the largest item in the tree and returns it. |
956 | | -// If no such item exists, returns nil. |
957 | | -func (t *BTree) DeleteMax() Item { |
958 | | - i, _ := (*BTreeG[Item])(t).DeleteMax() |
959 | | - return i |
960 | | -} |
961 | | - |
962 | | -// DeleteMin removes the smallest item in the tree and returns it. |
963 | | -// If no such item exists, returns nil. |
964 | | -func (t *BTree) DeleteMin() Item { |
965 | | - i, _ := (*BTreeG[Item])(t).DeleteMin() |
966 | | - return i |
967 | | -} |
968 | | - |
969 | | -// Get looks for the key item in the tree, returning it. It returns nil if |
970 | | -// unable to find that item. |
971 | | -func (t *BTree) Get(key Item) Item { |
972 | | - i, _ := (*BTreeG[Item])(t).Get(key) |
973 | | - return i |
974 | | -} |
975 | | - |
976 | | -// Max returns the largest item in the tree, or nil if the tree is empty. |
977 | | -func (t *BTree) Max() Item { |
978 | | - i, _ := (*BTreeG[Item])(t).Max() |
979 | | - return i |
980 | | -} |
981 | | - |
982 | | -// Min returns the smallest item in the tree, or nil if the tree is empty. |
983 | | -func (t *BTree) Min() Item { |
984 | | - i, _ := (*BTreeG[Item])(t).Min() |
985 | | - return i |
986 | | -} |
987 | | - |
988 | | -// Has returns true if the given key is in the tree. |
989 | | -func (t *BTree) Has(key Item) bool { |
990 | | - return (*BTreeG[Item])(t).Has(key) |
991 | | -} |
992 | | - |
993 | | -// ReplaceOrInsert adds the given item to the tree. If an item in the tree |
994 | | -// already equals the given one, it is removed from the tree and returned. |
995 | | -// Otherwise, nil is returned. |
996 | | -// |
997 | | -// nil cannot be added to the tree (will panic). |
998 | | -func (t *BTree) ReplaceOrInsert(item Item) Item { |
999 | | - i, _ := (*BTreeG[Item])(t).ReplaceOrInsert(item) |
1000 | | - return i |
1001 | | -} |
1002 | | - |
1003 | | -// AscendRange calls the iterator for every value in the tree within the range |
1004 | | -// [greaterOrEqual, lessThan), until iterator returns false. |
1005 | | -func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) { |
1006 | | - (*BTreeG[Item])(t).AscendRange(greaterOrEqual, lessThan, (ItemIteratorG[Item])(iterator)) |
1007 | | -} |
1008 | | - |
1009 | | -// AscendLessThan calls the iterator for every value in the tree within the range |
1010 | | -// [first, pivot), until iterator returns false. |
1011 | | -func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) { |
1012 | | - (*BTreeG[Item])(t).AscendLessThan(pivot, (ItemIteratorG[Item])(iterator)) |
1013 | | -} |
1014 | | - |
1015 | | -// AscendGreaterOrEqual calls the iterator for every value in the tree within |
1016 | | -// the range [pivot, last], until iterator returns false. |
1017 | | -func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { |
1018 | | - (*BTreeG[Item])(t).AscendGreaterOrEqual(pivot, (ItemIteratorG[Item])(iterator)) |
1019 | | -} |
1020 | | - |
1021 | | -// Ascend calls the iterator for every value in the tree within the range |
1022 | | -// [first, last], until iterator returns false. |
1023 | | -func (t *BTree) Ascend(iterator ItemIterator) { |
1024 | | - (*BTreeG[Item])(t).Ascend((ItemIteratorG[Item])(iterator)) |
1025 | | -} |
1026 | | - |
1027 | | -// DescendRange calls the iterator for every value in the tree within the range |
1028 | | -// [lessOrEqual, greaterThan), until iterator returns false. |
1029 | | -func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) { |
1030 | | - (*BTreeG[Item])(t).DescendRange(lessOrEqual, greaterThan, (ItemIteratorG[Item])(iterator)) |
1031 | | -} |
1032 | | - |
1033 | | -// DescendLessOrEqual calls the iterator for every value in the tree within the range |
1034 | | -// [pivot, first], until iterator returns false. |
1035 | | -func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) { |
1036 | | - (*BTreeG[Item])(t).DescendLessOrEqual(pivot, (ItemIteratorG[Item])(iterator)) |
1037 | | -} |
1038 | | - |
1039 | | -// DescendGreaterThan calls the iterator for every value in the tree within |
1040 | | -// the range [last, pivot), until iterator returns false. |
1041 | | -func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) { |
1042 | | - (*BTreeG[Item])(t).DescendGreaterThan(pivot, (ItemIteratorG[Item])(iterator)) |
1043 | | -} |
1044 | | - |
1045 | | -// Descend calls the iterator for every value in the tree within the range |
1046 | | -// [last, first], until iterator returns false. |
1047 | | -func (t *BTree) Descend(iterator ItemIterator) { |
1048 | | - (*BTreeG[Item])(t).Descend((ItemIteratorG[Item])(iterator)) |
1049 | | -} |
1050 | | - |
1051 | | -// Len returns the number of items currently in the tree. |
1052 | | -func (t *BTree) Len() int { |
1053 | | - return (*BTreeG[Item])(t).Len() |
1054 | | -} |
1055 | | - |
1056 | | -// Clear removes all items from the btree. If addNodesToFreelist is true, |
1057 | | -// t's nodes are added to its freelist as part of this call, until the freelist |
1058 | | -// is full. Otherwise, the root node is simply dereferenced and the subtree |
1059 | | -// left to Go's normal GC processes. |
1060 | | -// |
1061 | | -// This can be much faster |
1062 | | -// than calling Delete on all elements, because that requires finding/removing |
1063 | | -// each element in the tree and updating the tree accordingly. It also is |
1064 | | -// somewhat faster than creating a new tree to replace the old one, because |
1065 | | -// nodes from the old tree are reclaimed into the freelist for use by the new |
1066 | | -// one, instead of being lost to the garbage collector. |
1067 | | -// |
1068 | | -// This call takes: |
1069 | | -// |
1070 | | -// O(1): when addNodesToFreelist is false, this is a single operation. |
1071 | | -// O(1): when the freelist is already full, it breaks out immediately |
1072 | | -// O(freelist size): when the freelist is empty and the nodes are all owned |
1073 | | -// by this tree, nodes are added to the freelist until full. |
1074 | | -// O(tree size): when all nodes are owned by another tree, all nodes are |
1075 | | -// iterated over looking for nodes to add to the freelist, and due to |
1076 | | -// ownership, none are. |
1077 | | -func (t *BTree) Clear(addNodesToFreelist bool) { |
1078 | | - (*BTreeG[Item])(t).Clear(addNodesToFreelist) |
1079 | | -} |
0 commit comments