From 8a4d7bd8736730d792a76cc64ca57f16671c0824 Mon Sep 17 00:00:00 2001
From: a
Date: Sat, 24 Dec 2022 14:58:04 -0600
Subject: [PATCH 1/4] reorganize
---
btreeg.go | 953 -------------------------------------------
btreeg_deprecated.go | 27 ++
btreeg_impl.go | 693 +++++++++++++++++++++++++++++++
btreeg_iter.go | 238 +++++++++++
4 files changed, 958 insertions(+), 953 deletions(-)
create mode 100644 btreeg_deprecated.go
create mode 100644 btreeg_impl.go
create mode 100644 btreeg_iter.go
diff --git a/btreeg.go b/btreeg.go
index 86b8990..fa65073 100644
--- a/btreeg.go
+++ b/btreeg.go
@@ -61,135 +61,12 @@ func NewBTreeGOptions[T any](less func(a, b T) bool, opts Options) *BTreeG[T] {
return tr
}
-func (tr *BTreeG[T]) init(degree int) {
- if tr.min != 0 {
- return
- }
- tr.min, tr.max = degreeToMinMax(degree)
- _, tr.copyItems = ((interface{})(tr.empty)).(copier[T])
- if !tr.copyItems {
- _, tr.isoCopyItems = ((interface{})(tr.empty)).(isoCopier[T])
- }
-}
-
// Less is a convenience function that performs a comparison of two items
// using the same "less" function provided to New.
func (tr *BTreeG[T]) Less(a, b T) bool {
return tr.less(a, b)
}
-func (tr *BTreeG[T]) newNode(leaf bool) *node[T] {
- n := &node[T]{isoid: tr.isoid}
- if !leaf {
- n.children = new([]*node[T])
- }
- return n
-}
-
-// leaf returns true if the node is a leaf.
-func (n *node[T]) leaf() bool {
- return n.children == nil
-}
-
-func (tr *BTreeG[T]) bsearch(n *node[T], key T) (index int, found bool) {
- low, high := 0, len(n.items)
- for low < high {
- h := (low + high) / 2
- if !tr.less(key, n.items[h]) {
- low = h + 1
- } else {
- high = h
- }
- }
- if low > 0 && !tr.less(n.items[low-1], key) {
- return low - 1, true
- }
- return low, false
-}
-
-func (tr *BTreeG[T]) find(n *node[T], key T, hint *PathHint, depth int,
-) (index int, found bool) {
- if hint == nil {
- return tr.bsearch(n, key)
- }
- return tr.hintsearch(n, key, hint, depth)
-}
-
-func (tr *BTreeG[T]) hintsearch(n *node[T], key T, hint *PathHint, depth int,
-) (index int, found bool) {
- // Best case finds the exact match, updates the hint and returns.
- // Worst case, updates the low and high bounds to binary search between.
- low := 0
- high := len(n.items) - 1
- if depth < 8 && hint.used[depth] {
- index = int(hint.path[depth])
- if index >= len(n.items) {
- // tail item
- if tr.Less(n.items[len(n.items)-1], key) {
- index = len(n.items)
- goto path_match
- }
- index = len(n.items) - 1
- }
- if tr.Less(key, n.items[index]) {
- if index == 0 || tr.Less(n.items[index-1], key) {
- goto path_match
- }
- high = index - 1
- } else if tr.Less(n.items[index], key) {
- low = index + 1
- } else {
- found = true
- goto path_match
- }
- }
-
- // Do a binary search between low and high
- // keep on going until low > high, where the guarantee on low is that
- // key >= items[low - 1]
- for low <= high {
- mid := low + ((high+1)-low)/2
- // if key >= n.items[mid], low = mid + 1
- // which implies that key >= everything below low
- if !tr.Less(key, n.items[mid]) {
- low = mid + 1
- } else {
- high = mid - 1
- }
- }
-
- // if low > 0, n.items[low - 1] >= key,
- // we have from before that key >= n.items[low - 1]
- // therefore key = n.items[low - 1],
- // and we have found the entry for key.
- // Otherwise we must keep searching for the key in index `low`.
- if low > 0 && !tr.Less(n.items[low-1], key) {
- index = low - 1
- found = true
- } else {
- index = low
- found = false
- }
-
-path_match:
- if depth < 8 {
- hint.used[depth] = true
- var pathIndex uint8
- if n.leaf() && found {
- pathIndex = uint8(index + 1)
- } else {
- pathIndex = uint8(index)
- }
- if pathIndex != hint.path[depth] {
- hint.path[depth] = pathIndex
- for i := depth + 1; i < 8; i++ {
- hint.used[i] = false
- }
- }
- }
- return index, found
-}
-
// SetHint sets or replace a value for a key using a path hint
func (tr *BTreeG[T]) SetHint(item T, hint *PathHint) (prev T, replaced bool) {
if tr.locks {
@@ -202,151 +79,10 @@ func (tr *BTreeG[T]) SetHint(item T, hint *PathHint) (prev T, replaced bool) {
return prev, replaced
}
-func (tr *BTreeG[T]) setHint(item T, hint *PathHint) (prev T, replaced bool) {
- if tr.root == nil {
- tr.init(0)
- tr.root = tr.newNode(true)
- tr.root.items = append([]T{}, item)
- tr.root.count = 1
- tr.count = 1
- return tr.empty, false
- }
- prev, replaced, split := tr.nodeSet(&tr.root, item, hint, 0)
- if split {
- left := tr.isoLoad(&tr.root, true)
- right, median := tr.nodeSplit(left)
- tr.root = tr.newNode(false)
- *tr.root.children = make([]*node[T], 0, tr.max+1)
- *tr.root.children = append([]*node[T]{}, left, right)
- tr.root.items = append([]T{}, median)
- tr.root.updateCount()
- return tr.setHint(item, hint)
- }
- if replaced {
- return prev, true
- }
- tr.count++
- return tr.empty, false
-}
-
// Set or replace a value for a key
func (tr *BTreeG[T]) Set(item T) (T, bool) {
return tr.SetHint(item, nil)
}
-
-func (tr *BTreeG[T]) nodeSplit(n *node[T]) (right *node[T], median T) {
- i := tr.max / 2
- median = n.items[i]
-
- // right node
- right = tr.newNode(n.leaf())
- right.items = n.items[i+1:]
- if !n.leaf() {
- *right.children = (*n.children)[i+1:]
- }
- right.updateCount()
-
- // left node
- n.items[i] = tr.empty
- n.items = n.items[:i:i]
- if !n.leaf() {
- *n.children = (*n.children)[: i+1 : i+1]
- }
- n.updateCount()
-
- return right, median
-}
-
-func (n *node[T]) updateCount() {
- n.count = len(n.items)
- if !n.leaf() {
- for i := 0; i < len(*n.children); i++ {
- n.count += (*n.children)[i].count
- }
- }
-}
-
-// Copy the node for safe isolation.
-func (tr *BTreeG[T]) copy(n *node[T]) *node[T] {
- n2 := new(node[T])
- n2.isoid = tr.isoid
- n2.count = n.count
- n2.items = make([]T, len(n.items), cap(n.items))
- copy(n2.items, n.items)
- if tr.copyItems {
- for i := 0; i < len(n2.items); i++ {
- n2.items[i] = ((interface{})(n2.items[i])).(copier[T]).Copy()
- }
- } else if tr.isoCopyItems {
- for i := 0; i < len(n2.items); i++ {
- n2.items[i] = ((interface{})(n2.items[i])).(isoCopier[T]).IsoCopy()
- }
- }
- if !n.leaf() {
- n2.children = new([]*node[T])
- *n2.children = make([]*node[T], len(*n.children), tr.max+1)
- copy(*n2.children, *n.children)
- }
- return n2
-}
-
-// isoLoad loads the provided node and, if needed, performs a copy-on-write.
-func (tr *BTreeG[T]) isoLoad(cn **node[T], mut bool) *node[T] {
- if mut && (*cn).isoid != tr.isoid {
- *cn = tr.copy(*cn)
- }
- return *cn
-}
-
-func (tr *BTreeG[T]) nodeSet(cn **node[T], item T,
- hint *PathHint, depth int,
-) (prev T, replaced bool, split bool) {
- if (*cn).isoid != tr.isoid {
- *cn = tr.copy(*cn)
- }
- n := *cn
- var i int
- var found bool
- if hint == nil {
- i, found = tr.bsearch(n, item)
- } else {
- i, found = tr.hintsearch(n, item, hint, depth)
- }
- if found {
- prev = n.items[i]
- n.items[i] = item
- return prev, true, false
- }
- if n.leaf() {
- if len(n.items) == tr.max {
- return tr.empty, false, true
- }
- n.items = append(n.items, tr.empty)
- copy(n.items[i+1:], n.items[i:])
- n.items[i] = item
- n.count++
- return tr.empty, false, false
- }
- prev, replaced, split = tr.nodeSet(&(*n.children)[i], item, hint, depth+1)
- if split {
- if len(n.items) == tr.max {
- return tr.empty, false, true
- }
- right, median := tr.nodeSplit((*n.children)[i])
- *n.children = append(*n.children, nil)
- copy((*n.children)[i+1:], (*n.children)[i:])
- (*n.children)[i+1] = right
- n.items = append(n.items, tr.empty)
- copy(n.items[i+1:], n.items[i:])
- n.items[i] = median
- return tr.nodeSet(&n, item, hint, depth)
- }
- if !replaced {
- n.count++
- }
- return prev, replaced, false
-}
-
func (tr *BTreeG[T]) Scan(iter func(item T) bool) {
tr.scan(iter, false)
}
@@ -364,28 +100,6 @@ func (tr *BTreeG[T]) scan(iter func(item T) bool, mut bool) {
tr.nodeScan(&tr.root, iter, mut)
}
-func (tr *BTreeG[T]) nodeScan(cn **node[T], iter func(item T) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- for i := 0; i < len(n.items); i++ {
- if !iter(n.items[i]) {
- return false
- }
- }
- return true
- }
- for i := 0; i < len(n.items); i++ {
- if !tr.nodeScan(&(*n.children)[i], iter, mut) {
- return false
- }
- if !iter(n.items[i]) {
- return false
- }
- }
- return tr.nodeScan(&(*n.children)[len(*n.children)-1], iter, mut)
-}
-
// Get a value for key
func (tr *BTreeG[T]) Get(key T) (T, bool) {
return tr.getHint(key, nil, false)
@@ -403,29 +117,6 @@ func (tr *BTreeG[T]) GetHintMut(key T, hint *PathHint) (value T, ok bool) {
return tr.getHint(key, hint, true)
}
-// GetHint gets a value for key using a path hint
-func (tr *BTreeG[T]) getHint(key T, hint *PathHint, mut bool) (T, bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return tr.empty, false
- }
- n := tr.isoLoad(&tr.root, mut)
- depth := 0
- for {
- i, found := tr.find(n, key, hint, depth)
- if found {
- return n.items[i], true
- }
- if n.children == nil {
- return tr.empty, false
- }
- n = tr.isoLoad(&(*n.children)[i], mut)
- depth++
- }
-}
-
// Len returns the number of items in the tree
func (tr *BTreeG[T]) Len() int {
return tr.count
@@ -447,156 +138,6 @@ func (tr *BTreeG[T]) DeleteHint(key T, hint *PathHint) (T, bool) {
return tr.deleteHint(key, hint)
}
-func (tr *BTreeG[T]) deleteHint(key T, hint *PathHint) (T, bool) {
- if tr.root == nil {
- return tr.empty, false
- }
- prev, deleted := tr.delete(&tr.root, false, key, hint, 0)
- if !deleted {
- return tr.empty, false
- }
- if len(tr.root.items) == 0 && !tr.root.leaf() {
- tr.root = (*tr.root.children)[0]
- }
- tr.count--
- if tr.count == 0 {
- tr.root = nil
- }
- return prev, true
-}
-
-func (tr *BTreeG[T]) delete(cn **node[T], max bool, key T,
- hint *PathHint, depth int,
-) (T, bool) {
- n := tr.isoLoad(cn, true)
- var i int
- var found bool
- if max {
- i, found = len(n.items)-1, true
- } else {
- i, found = tr.find(n, key, hint, depth)
- }
- if n.leaf() {
- if found {
- // found the items at the leaf, remove it and return.
- prev := n.items[i]
- copy(n.items[i:], n.items[i+1:])
- n.items[len(n.items)-1] = tr.empty
- n.items = n.items[:len(n.items)-1]
- n.count--
- return prev, true
- }
- return tr.empty, false
- }
-
- var prev T
- var deleted bool
- if found {
- if max {
- i++
- prev, deleted = tr.delete(&(*n.children)[i], true, tr.empty, nil, 0)
- } else {
- prev = n.items[i]
- maxItem, _ := tr.delete(&(*n.children)[i], true, tr.empty, nil, 0)
- deleted = true
- n.items[i] = maxItem
- }
- } else {
- prev, deleted = tr.delete(&(*n.children)[i], max, key, hint, depth+1)
- }
- if !deleted {
- return tr.empty, false
- }
- n.count--
- if len((*n.children)[i].items) < tr.min {
- tr.nodeRebalance(n, i)
- }
- return prev, true
-}
-
-// nodeRebalance rebalances the child nodes following a delete operation.
-// Provide the index of the child node with the number of items that fell
-// below minItems.
-func (tr *BTreeG[T]) nodeRebalance(n *node[T], i int) {
- if i == len(n.items) {
- i--
- }
-
- // ensure copy-on-write
- left := tr.isoLoad(&(*n.children)[i], true)
- right := tr.isoLoad(&(*n.children)[i+1], true)
-
- if len(left.items)+len(right.items) < tr.max {
- // Merges the left and right children nodes together as a single node
- // that includes (left,item,right), and places the contents into the
- // existing left node. Delete the right node altogether and move the
- // following items and child nodes to the left by one slot.
-
- // merge (left,item,right)
- left.items = append(left.items, n.items[i])
- left.items = append(left.items, right.items...)
- if !left.leaf() {
- *left.children = append(*left.children, *right.children...)
- }
- left.count += right.count + 1
-
- // move the items over one slot
- copy(n.items[i:], n.items[i+1:])
- n.items[len(n.items)-1] = tr.empty
- n.items = n.items[:len(n.items)-1]
-
- // move the children over one slot
- copy((*n.children)[i+1:], (*n.children)[i+2:])
- (*n.children)[len(*n.children)-1] = nil
- (*n.children) = (*n.children)[:len(*n.children)-1]
- } else if len(left.items) > len(right.items) {
- // move left -> right over one slot
-
- // Move the item of the parent node at index into the right-node first
- // slot, and move the left-node last item into the previously moved
- // parent item slot.
- right.items = append(right.items, tr.empty)
- copy(right.items[1:], right.items)
- right.items[0] = n.items[i]
- right.count++
- n.items[i] = left.items[len(left.items)-1]
- left.items[len(left.items)-1] = tr.empty
- left.items = left.items[:len(left.items)-1]
- left.count--
-
- if !left.leaf() {
- // move the left-node last child into the right-node first slot
- *right.children = append(*right.children, nil)
- copy((*right.children)[1:], *right.children)
- (*right.children)[0] = (*left.children)[len(*left.children)-1]
- (*left.children)[len(*left.children)-1] = nil
- (*left.children) = (*left.children)[:len(*left.children)-1]
- left.count -= (*right.children)[0].count
- right.count += (*right.children)[0].count
- }
- } else {
- // move left <- right over one slot
-
- // Same as above but the other direction
- left.items = append(left.items, n.items[i])
- left.count++
- n.items[i] = right.items[0]
- copy(right.items, right.items[1:])
- right.items[len(right.items)-1] = tr.empty
- right.items = right.items[:len(right.items)-1]
- right.count--
-
- if !left.leaf() {
- *left.children = append(*left.children, (*right.children)[0])
- copy(*right.children, (*right.children)[1:])
- (*right.children)[len(*right.children)-1] = nil
- *right.children = (*right.children)[:len(*right.children)-1]
- left.count += (*left.children)[len(*left.children)-1].count
- right.count -= (*left.children)[len(*left.children)-1].count
- }
- }
-}
-
// Ascend the tree within the range [pivot, last]
// Pass nil for pivot to scan all item in ascending order
// Return false to stop iterating
@@ -606,47 +147,6 @@ func (tr *BTreeG[T]) Ascend(pivot T, iter func(item T) bool) {
func (tr *BTreeG[T]) AscendMut(pivot T, iter func(item T) bool) {
tr.ascend(pivot, iter, true)
}
-func (tr *BTreeG[T]) ascend(pivot T, iter func(item T) bool, mut bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return
- }
- tr.nodeAscend(&tr.root, pivot, nil, 0, iter, mut)
-}
-
-// The return value of this function determines whether we should keep iterating
-// upon this functions return.
-func (tr *BTreeG[T]) nodeAscend(cn **node[T], pivot T, hint *PathHint,
- depth int, iter func(item T) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- i, found := tr.find(n, pivot, hint, depth)
- if !found {
- if !n.leaf() {
- if !tr.nodeAscend(&(*n.children)[i], pivot, hint, depth+1, iter,
- mut) {
- return false
- }
- }
- }
- // We are either in the case that
- // - node is found, we should iterate through it starting at `i`,
- // the index it was located at.
- // - node is not found, and TODO: fill in.
- for ; i < len(n.items); i++ {
- if !iter(n.items[i]) {
- return false
- }
- if !n.leaf() {
- if !tr.nodeScan(&(*n.children)[i+1], iter, mut) {
- return false
- }
- }
- }
- return true
-}
func (tr *BTreeG[T]) Reverse(iter func(item T) bool) {
tr.reverse(iter, false)
@@ -664,31 +164,6 @@ func (tr *BTreeG[T]) reverse(iter func(item T) bool, mut bool) {
tr.nodeReverse(&tr.root, iter, mut)
}
-func (tr *BTreeG[T]) nodeReverse(cn **node[T], iter func(item T) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- for i := len(n.items) - 1; i >= 0; i-- {
- if !iter(n.items[i]) {
- return false
- }
- }
- return true
- }
- if !tr.nodeReverse(&(*n.children)[len(*n.children)-1], iter, mut) {
- return false
- }
- for i := len(n.items) - 1; i >= 0; i-- {
- if !iter(n.items[i]) {
- return false
- }
- if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
- return false
- }
- }
- return true
-}
-
// Descend the tree within the range [pivot, first]
// Pass nil for pivot to scan all item in descending order
// Return false to stop iterating
@@ -708,33 +183,6 @@ func (tr *BTreeG[T]) descend(pivot T, iter func(item T) bool, mut bool) {
tr.nodeDescend(&tr.root, pivot, nil, 0, iter, mut)
}
-func (tr *BTreeG[T]) nodeDescend(cn **node[T], pivot T, hint *PathHint,
- depth int, iter func(item T) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- i, found := tr.find(n, pivot, hint, depth)
- if !found {
- if !n.leaf() {
- if !tr.nodeDescend(&(*n.children)[i], pivot, hint, depth+1, iter,
- mut) {
- return false
- }
- }
- i--
- }
- for ; i >= 0; i-- {
- if !iter(n.items[i]) {
- return false
- }
- if !n.leaf() {
- if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
- return false
- }
- }
- }
- return true
-}
-
// Load is for bulk loading pre-sorted items
func (tr *BTreeG[T]) Load(item T) (T, bool) {
if tr.lock(true) {
@@ -780,22 +228,6 @@ func (tr *BTreeG[T]) MinMut() (T, bool) {
return tr.minMut(true)
}
-func (tr *BTreeG[T]) minMut(mut bool) (T, bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return tr.empty, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- if n.leaf() {
- return n.items[0], true
- }
- n = tr.isoLoad(&(*n.children)[0], mut)
- }
-}
-
// Max returns the maximum item in tree.
// Returns nil if the tree has no items.
func (tr *BTreeG[T]) Max() (T, bool) {
@@ -806,22 +238,6 @@ func (tr *BTreeG[T]) MaxMut() (T, bool) {
return tr.maxMut(true)
}
-func (tr *BTreeG[T]) maxMut(mut bool) (T, bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return tr.empty, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- if n.leaf() {
- return n.items[len(n.items)-1], true
- }
- n = tr.isoLoad(&(*n.children)[len(*n.children)-1], mut)
- }
-}
-
// PopMin removes the minimum item in tree and returns it.
// Returns nil if the tree has no items.
func (tr *BTreeG[T]) PopMin() (T, bool) {
@@ -911,30 +327,6 @@ func (tr *BTreeG[T]) GetAt(index int) (T, bool) {
func (tr *BTreeG[T]) GetAtMut(index int) (T, bool) {
return tr.getAt(index, true)
}
-func (tr *BTreeG[T]) getAt(index int, mut bool) (T, bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil || index < 0 || index >= tr.count {
- return tr.empty, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- if n.leaf() {
- return n.items[index], true
- }
- i := 0
- for ; i < len(n.items); i++ {
- if index < (*n.children)[i].count {
- break
- } else if index == (*n.children)[i].count {
- return n.items[i], true
- }
- index -= (*n.children)[i].count + 1
- }
- n = tr.isoLoad(&(*n.children)[i], mut)
- }
-}
// DeleteAt deletes the item at index.
// Return nil if the tree is empty or the index is out of bounds.
@@ -1026,38 +418,6 @@ func (tr *BTreeG[T]) Walk(iter func(item []T) bool) {
func (tr *BTreeG[T]) WalkMut(iter func(item []T) bool) {
tr.walk(iter, true)
}
-func (tr *BTreeG[T]) walk(iter func(item []T) bool, mut bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return
- }
- tr.nodeWalk(&tr.root, iter, mut)
-}
-
-func (tr *BTreeG[T]) nodeWalk(cn **node[T], iter func(item []T) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- if !iter(n.items) {
- return false
- }
- } else {
- for i := 0; i < len(n.items); i++ {
- if !tr.nodeWalk(&(*n.children)[i], iter, mut) {
- return false
- }
- if !iter(n.items[i : i+1]) {
- return false
- }
- }
- if !tr.nodeWalk(&(*n.children)[len(n.items)], iter, mut) {
- return false
- }
- }
- return true
-}
// Copy the tree. This is a copy-on-write operation and is very fast because
// it only performs a shadowed copy.
@@ -1076,316 +436,3 @@ func (tr *BTreeG[T]) IsoCopy() *BTreeG[T] {
tr2.isoid = newIsoID()
return tr2
}
-
-func (tr *BTreeG[T]) lock(write bool) bool {
- if tr.locks {
- if write {
- tr.mu.Lock()
- } else {
- tr.mu.RLock()
- }
- }
- return tr.locks
-}
-
-func (tr *BTreeG[T]) unlock(write bool) {
- if write {
- tr.mu.Unlock()
- } else {
- tr.mu.RUnlock()
- }
-}
-
-// Iter represents an iterator
-type IterG[T any] struct {
- tr *BTreeG[T]
- mut bool
- locked bool
- seeked bool
- atstart bool
- atend bool
- stack []iterStackItemG[T]
- item T
-}
-
-type iterStackItemG[T any] struct {
- n *node[T]
- i int
-}
-
-// Iter returns a read-only iterator.
-// The Release method must be called finished with iterator.
-func (tr *BTreeG[T]) Iter() IterG[T] {
- return tr.iter(false)
-}
-
-func (tr *BTreeG[T]) IterMut() IterG[T] {
- return tr.iter(true)
-}
-
-func (tr *BTreeG[T]) iter(mut bool) IterG[T] {
- var iter IterG[T]
- iter.tr = tr
- iter.mut = mut
- iter.locked = tr.lock(iter.mut)
- return iter
-}
-
-// Seek to item greater-or-equal-to key.
-// Returns false if there was no item found.
-func (iter *IterG[T]) Seek(key T) bool {
- if iter.tr == nil {
- return false
- }
- iter.seeked = true
- iter.stack = iter.stack[:0]
- if iter.tr.root == nil {
- return false
- }
- n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
- for {
- i, found := iter.tr.find(n, key, nil, 0)
- iter.stack = append(iter.stack, iterStackItemG[T]{n, i})
- if found {
- iter.item = n.items[i]
- return true
- }
- if n.leaf() {
- iter.stack[len(iter.stack)-1].i--
- return iter.Next()
- }
- n = iter.tr.isoLoad(&(*n.children)[i], iter.mut)
- }
-}
-
-// First moves iterator to first item in tree.
-// Returns false if the tree is empty.
-func (iter *IterG[T]) First() bool {
- if iter.tr == nil {
- return false
- }
- iter.atend = false
- iter.atstart = false
- iter.seeked = true
- iter.stack = iter.stack[:0]
- if iter.tr.root == nil {
- return false
- }
- n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
- for {
- iter.stack = append(iter.stack, iterStackItemG[T]{n, 0})
- if n.leaf() {
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
- }
- s := &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Last moves iterator to last item in tree.
-// Returns false if the tree is empty.
-func (iter *IterG[T]) Last() bool {
- if iter.tr == nil {
- return false
- }
- iter.seeked = true
- iter.stack = iter.stack[:0]
- if iter.tr.root == nil {
- return false
- }
- n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
- for {
- iter.stack = append(iter.stack, iterStackItemG[T]{n, len(n.items)})
- if n.leaf() {
- iter.stack[len(iter.stack)-1].i--
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
- }
- s := &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Release the iterator.
-func (iter *IterG[T]) Release() {
- if iter.tr == nil {
- return
- }
- if iter.locked {
- iter.tr.unlock(iter.mut)
- iter.locked = false
- }
- iter.stack = nil
- iter.tr = nil
-}
-
-// Next moves iterator to the next item in iterator.
-// Returns false if the tree is empty or the iterator is at the end of
-// the tree.
-func (iter *IterG[T]) Next() bool {
- if iter.tr == nil {
- return false
- }
- if !iter.seeked {
- return iter.First()
- }
- if len(iter.stack) == 0 {
- if iter.atstart {
- return iter.First() && iter.Next()
- }
- return false
- }
- s := &iter.stack[len(iter.stack)-1]
- s.i++
- if s.n.leaf() {
- if s.i == len(s.n.items) {
- for {
- iter.stack = iter.stack[:len(iter.stack)-1]
- if len(iter.stack) == 0 {
- iter.atend = true
- return false
- }
- s = &iter.stack[len(iter.stack)-1]
- if s.i < len(s.n.items) {
- break
- }
- }
- }
- } else {
- n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
- for {
- iter.stack = append(iter.stack, iterStackItemG[T]{n, 0})
- if n.leaf() {
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
- }
- }
- s = &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Prev moves iterator to the previous item in iterator.
-// Returns false if the tree is empty or the iterator is at the beginning of
-// the tree.
-func (iter *IterG[T]) Prev() bool {
- if iter.tr == nil {
- return false
- }
- if !iter.seeked {
- return false
- }
- if len(iter.stack) == 0 {
- if iter.atend {
- return iter.Last() && iter.Prev()
- }
- return false
- }
- s := &iter.stack[len(iter.stack)-1]
- if s.n.leaf() {
- s.i--
- if s.i == -1 {
- for {
- iter.stack = iter.stack[:len(iter.stack)-1]
- if len(iter.stack) == 0 {
- iter.atstart = true
- return false
- }
- s = &iter.stack[len(iter.stack)-1]
- s.i--
- if s.i > -1 {
- break
- }
- }
- }
- } else {
- n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
- for {
- iter.stack = append(iter.stack, iterStackItemG[T]{n, len(n.items)})
- if n.leaf() {
- iter.stack[len(iter.stack)-1].i--
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
- }
- }
- s = &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Item returns the current iterator item.
-func (iter *IterG[T]) Item() T {
- return iter.item
-}
-
-// Items returns all the items in order.
-func (tr *BTreeG[T]) Items() []T {
- return tr.items(false)
-}
-
-func (tr *BTreeG[T]) ItemsMut() []T {
- return tr.items(true)
-}
-
-func (tr *BTreeG[T]) items(mut bool) []T {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- items := make([]T, 0, tr.Len())
- if tr.root != nil {
- items = tr.nodeItems(&tr.root, items, mut)
- }
- return items
-}
-
-func (tr *BTreeG[T]) nodeItems(cn **node[T], items []T, mut bool) []T {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- return append(items, n.items...)
- }
- for i := 0; i < len(n.items); i++ {
- items = tr.nodeItems(&(*n.children)[i], items, mut)
- items = append(items, n.items[i])
- }
- return tr.nodeItems(&(*n.children)[len(*n.children)-1], items, mut)
-}
-
-// Clear will delete all items.
-func (tr *BTreeG[T]) Clear() {
- if tr.lock(true) {
- defer tr.unlock(true)
- }
- tr.root = nil
- tr.count = 0
-}
-
-// Generic BTree
-//
-// Deprecated: use BTreeG
-type Generic[T any] struct {
- *BTreeG[T]
-}
-
-// NewGeneric returns a generic BTree
-//
-// Deprecated: use NewBTreeG
-func NewGeneric[T any](less func(a, b T) bool) *Generic[T] {
- return &Generic[T]{NewBTreeGOptions(less, Options{})}
-}
-
-// NewGenericOptions returns a generic BTree
-//
-// Deprecated: use NewBTreeGOptions
-func NewGenericOptions[T any](less func(a, b T) bool, opts Options,
-) *Generic[T] {
- return &Generic[T]{NewBTreeGOptions(less, opts)}
-}
-
-func (tr *Generic[T]) Copy() *Generic[T] {
- return &Generic[T]{tr.BTreeG.Copy()}
-}
diff --git a/btreeg_deprecated.go b/btreeg_deprecated.go
new file mode 100644
index 0000000..72cfd59
--- /dev/null
+++ b/btreeg_deprecated.go
@@ -0,0 +1,27 @@
+package btree
+
+// Generic BTree
+//
+// Deprecated: use BTreeG
+type Generic[T any] struct {
+ *BTreeG[T]
+}
+
+// NewGeneric returns a generic BTree
+//
+// Deprecated: use NewBTreeG
+func NewGeneric[T any](less func(a, b T) bool) *Generic[T] {
+ return &Generic[T]{NewBTreeGOptions(less, Options{})}
+}
+
+// NewGenericOptions returns a generic BTree
+//
+// Deprecated: use NewBTreeGOptions
+func NewGenericOptions[T any](less func(a, b T) bool, opts Options,
+) *Generic[T] {
+ return &Generic[T]{NewBTreeGOptions(less, opts)}
+}
+
+func (tr *Generic[T]) Copy() *Generic[T] {
+ return &Generic[T]{tr.BTreeG.Copy()}
+}
diff --git a/btreeg_impl.go b/btreeg_impl.go
new file mode 100644
index 0000000..ee36a98
--- /dev/null
+++ b/btreeg_impl.go
@@ -0,0 +1,693 @@
+package btree
+
+func (tr *BTreeG[T]) init(degree int) {
+ if tr.min != 0 {
+ return
+ }
+ tr.min, tr.max = degreeToMinMax(degree)
+ _, tr.copyItems = ((interface{})(tr.empty)).(copier[T])
+ if !tr.copyItems {
+ _, tr.isoCopyItems = ((interface{})(tr.empty)).(isoCopier[T])
+ }
+}
+
+func (tr *BTreeG[T]) newNode(leaf bool) *node[T] {
+ n := &node[T]{isoid: tr.isoid}
+ if !leaf {
+ n.children = new([]*node[T])
+ }
+ return n
+}
+
+// leaf returns true if the node is a leaf.
+func (n *node[T]) leaf() bool {
+ return n.children == nil
+}
+
+func (tr *BTreeG[T]) bsearch(n *node[T], key T) (index int, found bool) {
+ low, high := 0, len(n.items)
+ for low < high {
+ h := (low + high) / 2
+ if !tr.less(key, n.items[h]) {
+ low = h + 1
+ } else {
+ high = h
+ }
+ }
+ if low > 0 && !tr.less(n.items[low-1], key) {
+ return low - 1, true
+ }
+ return low, false
+}
+
+func (tr *BTreeG[T]) find(n *node[T], key T, hint *PathHint, depth int,
+) (index int, found bool) {
+ if hint == nil {
+ return tr.bsearch(n, key)
+ }
+ return tr.hintsearch(n, key, hint, depth)
+}
+
+func (tr *BTreeG[T]) hintsearch(n *node[T], key T, hint *PathHint, depth int,
+) (index int, found bool) {
+ // Best case finds the exact match, updates the hint and returns.
+ // Worst case, updates the low and high bounds to binary search between.
+ low := 0
+ high := len(n.items) - 1
+ if depth < 8 && hint.used[depth] {
+ index = int(hint.path[depth])
+ if index >= len(n.items) {
+ // tail item
+ if tr.Less(n.items[len(n.items)-1], key) {
+ index = len(n.items)
+ goto path_match
+ }
+ index = len(n.items) - 1
+ }
+ if tr.Less(key, n.items[index]) {
+ if index == 0 || tr.Less(n.items[index-1], key) {
+ goto path_match
+ }
+ high = index - 1
+ } else if tr.Less(n.items[index], key) {
+ low = index + 1
+ } else {
+ found = true
+ goto path_match
+ }
+ }
+
+ // Do a binary search between low and high
+ // keep on going until low > high, where the guarantee on low is that
+ // key >= items[low - 1]
+ for low <= high {
+ mid := low + ((high+1)-low)/2
+ // if key >= n.items[mid], low = mid + 1
+ // which implies that key >= everything below low
+ if !tr.Less(key, n.items[mid]) {
+ low = mid + 1
+ } else {
+ high = mid - 1
+ }
+ }
+
+ // if low > 0, n.items[low - 1] >= key,
+ // we have from before that key >= n.items[low - 1]
+ // therefore key = n.items[low - 1],
+ // and we have found the entry for key.
+ // Otherwise we must keep searching for the key in index `low`.
+ if low > 0 && !tr.Less(n.items[low-1], key) {
+ index = low - 1
+ found = true
+ } else {
+ index = low
+ found = false
+ }
+
+path_match:
+ if depth < 8 {
+ hint.used[depth] = true
+ var pathIndex uint8
+ if n.leaf() && found {
+ pathIndex = uint8(index + 1)
+ } else {
+ pathIndex = uint8(index)
+ }
+ if pathIndex != hint.path[depth] {
+ hint.path[depth] = pathIndex
+ for i := depth + 1; i < 8; i++ {
+ hint.used[i] = false
+ }
+ }
+ }
+ return index, found
+}
+
+func (tr *BTreeG[T]) setHint(item T, hint *PathHint) (prev T, replaced bool) {
+ if tr.root == nil {
+ tr.init(0)
+ tr.root = tr.newNode(true)
+ tr.root.items = append([]T{}, item)
+ tr.root.count = 1
+ tr.count = 1
+ return tr.empty, false
+ }
+ prev, replaced, split := tr.nodeSet(&tr.root, item, hint, 0)
+ if split {
+ left := tr.isoLoad(&tr.root, true)
+ right, median := tr.nodeSplit(left)
+ tr.root = tr.newNode(false)
+ *tr.root.children = make([]*node[T], 0, tr.max+1)
+ *tr.root.children = append([]*node[T]{}, left, right)
+ tr.root.items = append([]T{}, median)
+ tr.root.updateCount()
+ return tr.setHint(item, hint)
+ }
+ if replaced {
+ return prev, true
+ }
+ tr.count++
+ return tr.empty, false
+}
+
+func (tr *BTreeG[T]) nodeSplit(n *node[T]) (right *node[T], median T) {
+ i := tr.max / 2
+ median = n.items[i]
+
+ // right node
+ right = tr.newNode(n.leaf())
+ right.items = n.items[i+1:]
+ if !n.leaf() {
+ *right.children = (*n.children)[i+1:]
+ }
+ right.updateCount()
+
+ // left node
+ n.items[i] = tr.empty
+ n.items = n.items[:i:i]
+ if !n.leaf() {
+ *n.children = (*n.children)[: i+1 : i+1]
+ }
+ n.updateCount()
+
+ return right, median
+}
+
+func (n *node[T]) updateCount() {
+ n.count = len(n.items)
+ if !n.leaf() {
+ for i := 0; i < len(*n.children); i++ {
+ n.count += (*n.children)[i].count
+ }
+ }
+}
+
+// Copy the node for safe isolation.
+func (tr *BTreeG[T]) copy(n *node[T]) *node[T] {
+ n2 := new(node[T])
+ n2.isoid = tr.isoid
+ n2.count = n.count
+ n2.items = make([]T, len(n.items), cap(n.items))
+ copy(n2.items, n.items)
+ if tr.copyItems {
+ for i := 0; i < len(n2.items); i++ {
+ n2.items[i] = ((interface{})(n2.items[i])).(copier[T]).Copy()
+ }
+ } else if tr.isoCopyItems {
+ for i := 0; i < len(n2.items); i++ {
+ n2.items[i] = ((interface{})(n2.items[i])).(isoCopier[T]).IsoCopy()
+ }
+ }
+ if !n.leaf() {
+ n2.children = new([]*node[T])
+ *n2.children = make([]*node[T], len(*n.children), tr.max+1)
+ copy(*n2.children, *n.children)
+ }
+ return n2
+}
+
+// isoLoad loads the provided node and, if needed, performs a copy-on-write.
+func (tr *BTreeG[T]) isoLoad(cn **node[T], mut bool) *node[T] {
+ if mut && (*cn).isoid != tr.isoid {
+ *cn = tr.copy(*cn)
+ }
+ return *cn
+}
+
+func (tr *BTreeG[T]) nodeSet(cn **node[T], item T,
+ hint *PathHint, depth int,
+) (prev T, replaced bool, split bool) {
+ if (*cn).isoid != tr.isoid {
+ *cn = tr.copy(*cn)
+ }
+ n := *cn
+ var i int
+ var found bool
+ if hint == nil {
+ i, found = tr.bsearch(n, item)
+ } else {
+ i, found = tr.hintsearch(n, item, hint, depth)
+ }
+ if found {
+ prev = n.items[i]
+ n.items[i] = item
+ return prev, true, false
+ }
+ if n.leaf() {
+ if len(n.items) == tr.max {
+ return tr.empty, false, true
+ }
+ n.items = append(n.items, tr.empty)
+ copy(n.items[i+1:], n.items[i:])
+ n.items[i] = item
+ n.count++
+ return tr.empty, false, false
+ }
+ prev, replaced, split = tr.nodeSet(&(*n.children)[i], item, hint, depth+1)
+ if split {
+ if len(n.items) == tr.max {
+ return tr.empty, false, true
+ }
+ right, median := tr.nodeSplit((*n.children)[i])
+ *n.children = append(*n.children, nil)
+ copy((*n.children)[i+1:], (*n.children)[i:])
+ (*n.children)[i+1] = right
+ n.items = append(n.items, tr.empty)
+ copy(n.items[i+1:], n.items[i:])
+ n.items[i] = median
+ return tr.nodeSet(&n, item, hint, depth)
+ }
+ if !replaced {
+ n.count++
+ }
+ return prev, replaced, false
+}
+
+func (tr *BTreeG[T]) nodeScan(cn **node[T], iter func(item T) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ for i := 0; i < len(n.items); i++ {
+ if !iter(n.items[i]) {
+ return false
+ }
+ }
+ return true
+ }
+ for i := 0; i < len(n.items); i++ {
+ if !tr.nodeScan(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ if !iter(n.items[i]) {
+ return false
+ }
+ }
+ return tr.nodeScan(&(*n.children)[len(*n.children)-1], iter, mut)
+}
+
+// GetHint gets a value for key using a path hint
+func (tr *BTreeG[T]) getHint(key T, hint *PathHint, mut bool) (T, bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return tr.empty, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ depth := 0
+ for {
+ i, found := tr.find(n, key, hint, depth)
+ if found {
+ return n.items[i], true
+ }
+ if n.children == nil {
+ return tr.empty, false
+ }
+ n = tr.isoLoad(&(*n.children)[i], mut)
+ depth++
+ }
+}
+
+func (tr *BTreeG[T]) deleteHint(key T, hint *PathHint) (T, bool) {
+ if tr.root == nil {
+ return tr.empty, false
+ }
+ prev, deleted := tr.delete(&tr.root, false, key, hint, 0)
+ if !deleted {
+ return tr.empty, false
+ }
+ if len(tr.root.items) == 0 && !tr.root.leaf() {
+ tr.root = (*tr.root.children)[0]
+ }
+ tr.count--
+ if tr.count == 0 {
+ tr.root = nil
+ }
+ return prev, true
+}
+
+func (tr *BTreeG[T]) delete(cn **node[T], max bool, key T,
+ hint *PathHint, depth int,
+) (T, bool) {
+ n := tr.isoLoad(cn, true)
+ var i int
+ var found bool
+ if max {
+ i, found = len(n.items)-1, true
+ } else {
+ i, found = tr.find(n, key, hint, depth)
+ }
+ if n.leaf() {
+ if found {
+ // found the items at the leaf, remove it and return.
+ prev := n.items[i]
+ copy(n.items[i:], n.items[i+1:])
+ n.items[len(n.items)-1] = tr.empty
+ n.items = n.items[:len(n.items)-1]
+ n.count--
+ return prev, true
+ }
+ return tr.empty, false
+ }
+
+ var prev T
+ var deleted bool
+ if found {
+ if max {
+ i++
+ prev, deleted = tr.delete(&(*n.children)[i], true, tr.empty, nil, 0)
+ } else {
+ prev = n.items[i]
+ maxItem, _ := tr.delete(&(*n.children)[i], true, tr.empty, nil, 0)
+ deleted = true
+ n.items[i] = maxItem
+ }
+ } else {
+ prev, deleted = tr.delete(&(*n.children)[i], max, key, hint, depth+1)
+ }
+ if !deleted {
+ return tr.empty, false
+ }
+ n.count--
+ if len((*n.children)[i].items) < tr.min {
+ tr.nodeRebalance(n, i)
+ }
+ return prev, true
+}
+
+// nodeRebalance rebalances the child nodes following a delete operation.
+// Provide the index of the child node with the number of items that fell
+// below minItems.
+func (tr *BTreeG[T]) nodeRebalance(n *node[T], i int) {
+ if i == len(n.items) {
+ i--
+ }
+
+ // ensure copy-on-write
+ left := tr.isoLoad(&(*n.children)[i], true)
+ right := tr.isoLoad(&(*n.children)[i+1], true)
+
+ if len(left.items)+len(right.items) < tr.max {
+ // Merges the left and right children nodes together as a single node
+ // that includes (left,item,right), and places the contents into the
+ // existing left node. Delete the right node altogether and move the
+ // following items and child nodes to the left by one slot.
+
+ // merge (left,item,right)
+ left.items = append(left.items, n.items[i])
+ left.items = append(left.items, right.items...)
+ if !left.leaf() {
+ *left.children = append(*left.children, *right.children...)
+ }
+ left.count += right.count + 1
+
+ // move the items over one slot
+ copy(n.items[i:], n.items[i+1:])
+ n.items[len(n.items)-1] = tr.empty
+ n.items = n.items[:len(n.items)-1]
+
+ // move the children over one slot
+ copy((*n.children)[i+1:], (*n.children)[i+2:])
+ (*n.children)[len(*n.children)-1] = nil
+ (*n.children) = (*n.children)[:len(*n.children)-1]
+ } else if len(left.items) > len(right.items) {
+ // move left -> right over one slot
+
+ // Move the item of the parent node at index into the right-node first
+ // slot, and move the left-node last item into the previously moved
+ // parent item slot.
+ right.items = append(right.items, tr.empty)
+ copy(right.items[1:], right.items)
+ right.items[0] = n.items[i]
+ right.count++
+ n.items[i] = left.items[len(left.items)-1]
+ left.items[len(left.items)-1] = tr.empty
+ left.items = left.items[:len(left.items)-1]
+ left.count--
+
+ if !left.leaf() {
+ // move the left-node last child into the right-node first slot
+ *right.children = append(*right.children, nil)
+ copy((*right.children)[1:], *right.children)
+ (*right.children)[0] = (*left.children)[len(*left.children)-1]
+ (*left.children)[len(*left.children)-1] = nil
+ (*left.children) = (*left.children)[:len(*left.children)-1]
+ left.count -= (*right.children)[0].count
+ right.count += (*right.children)[0].count
+ }
+ } else {
+ // move left <- right over one slot
+
+ // Same as above but the other direction
+ left.items = append(left.items, n.items[i])
+ left.count++
+ n.items[i] = right.items[0]
+ copy(right.items, right.items[1:])
+ right.items[len(right.items)-1] = tr.empty
+ right.items = right.items[:len(right.items)-1]
+ right.count--
+
+ if !left.leaf() {
+ *left.children = append(*left.children, (*right.children)[0])
+ copy(*right.children, (*right.children)[1:])
+ (*right.children)[len(*right.children)-1] = nil
+ *right.children = (*right.children)[:len(*right.children)-1]
+ left.count += (*left.children)[len(*left.children)-1].count
+ right.count -= (*left.children)[len(*left.children)-1].count
+ }
+ }
+}
+
+func (tr *BTreeG[T]) ascend(pivot T, iter func(item T) bool, mut bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return
+ }
+ tr.nodeAscend(&tr.root, pivot, nil, 0, iter, mut)
+}
+
+// The return value of this function determines whether we should keep iterating
+// upon this functions return.
+func (tr *BTreeG[T]) nodeAscend(cn **node[T], pivot T, hint *PathHint,
+ depth int, iter func(item T) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ i, found := tr.find(n, pivot, hint, depth)
+ if !found {
+ if !n.leaf() {
+ if !tr.nodeAscend(&(*n.children)[i], pivot, hint, depth+1, iter,
+ mut) {
+ return false
+ }
+ }
+ }
+ // We are either in the case that
+ // - node is found, we should iterate through it starting at `i`,
+ // the index it was located at.
+ // - node is not found, and TODO: fill in.
+ for ; i < len(n.items); i++ {
+ if !iter(n.items[i]) {
+ return false
+ }
+ if !n.leaf() {
+ if !tr.nodeScan(&(*n.children)[i+1], iter, mut) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (tr *BTreeG[T]) nodeReverse(cn **node[T], iter func(item T) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ for i := len(n.items) - 1; i >= 0; i-- {
+ if !iter(n.items[i]) {
+ return false
+ }
+ }
+ return true
+ }
+ if !tr.nodeReverse(&(*n.children)[len(*n.children)-1], iter, mut) {
+ return false
+ }
+ for i := len(n.items) - 1; i >= 0; i-- {
+ if !iter(n.items[i]) {
+ return false
+ }
+ if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ }
+ return true
+}
+
+func (tr *BTreeG[T]) nodeDescend(cn **node[T], pivot T, hint *PathHint,
+ depth int, iter func(item T) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ i, found := tr.find(n, pivot, hint, depth)
+ if !found {
+ if !n.leaf() {
+ if !tr.nodeDescend(&(*n.children)[i], pivot, hint, depth+1, iter,
+ mut) {
+ return false
+ }
+ }
+ i--
+ }
+ for ; i >= 0; i-- {
+ if !iter(n.items[i]) {
+ return false
+ }
+ if !n.leaf() {
+ if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (tr *BTreeG[T]) minMut(mut bool) (T, bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return tr.empty, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ if n.leaf() {
+ return n.items[0], true
+ }
+ n = tr.isoLoad(&(*n.children)[0], mut)
+ }
+}
+
+func (tr *BTreeG[T]) maxMut(mut bool) (T, bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return tr.empty, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ if n.leaf() {
+ return n.items[len(n.items)-1], true
+ }
+ n = tr.isoLoad(&(*n.children)[len(*n.children)-1], mut)
+ }
+}
+
+func (tr *BTreeG[T]) getAt(index int, mut bool) (T, bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil || index < 0 || index >= tr.count {
+ return tr.empty, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ if n.leaf() {
+ return n.items[index], true
+ }
+ i := 0
+ for ; i < len(n.items); i++ {
+ if index < (*n.children)[i].count {
+ break
+ } else if index == (*n.children)[i].count {
+ return n.items[i], true
+ }
+ index -= (*n.children)[i].count + 1
+ }
+ n = tr.isoLoad(&(*n.children)[i], mut)
+ }
+}
+
+func (tr *BTreeG[T]) walk(iter func(item []T) bool, mut bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return
+ }
+ tr.nodeWalk(&tr.root, iter, mut)
+}
+
+func (tr *BTreeG[T]) nodeWalk(cn **node[T], iter func(item []T) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ if !iter(n.items) {
+ return false
+ }
+ } else {
+ for i := 0; i < len(n.items); i++ {
+ if !tr.nodeWalk(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ if !iter(n.items[i : i+1]) {
+ return false
+ }
+ }
+ if !tr.nodeWalk(&(*n.children)[len(n.items)], iter, mut) {
+ return false
+ }
+ }
+ return true
+}
+
+func (tr *BTreeG[T]) lock(write bool) bool {
+ if tr.locks {
+ if write {
+ tr.mu.Lock()
+ } else {
+ tr.mu.RLock()
+ }
+ }
+ return tr.locks
+}
+
+func (tr *BTreeG[T]) unlock(write bool) {
+ if write {
+ tr.mu.Unlock()
+ } else {
+ tr.mu.RUnlock()
+ }
+}
+
+func (tr *BTreeG[T]) iter(mut bool) IterG[T] {
+ var iter IterG[T]
+ iter.tr = tr
+ iter.mut = mut
+ iter.locked = tr.lock(iter.mut)
+ return iter
+}
+
+func (tr *BTreeG[T]) items(mut bool) []T {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ items := make([]T, 0, tr.Len())
+ if tr.root != nil {
+ items = tr.nodeItems(&tr.root, items, mut)
+ }
+ return items
+}
+
+func (tr *BTreeG[T]) nodeItems(cn **node[T], items []T, mut bool) []T {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ return append(items, n.items...)
+ }
+ for i := 0; i < len(n.items); i++ {
+ items = tr.nodeItems(&(*n.children)[i], items, mut)
+ items = append(items, n.items[i])
+ }
+ return tr.nodeItems(&(*n.children)[len(*n.children)-1], items, mut)
+}
diff --git a/btreeg_iter.go b/btreeg_iter.go
new file mode 100644
index 0000000..0d78570
--- /dev/null
+++ b/btreeg_iter.go
@@ -0,0 +1,238 @@
+package btree
+
+// Iter represents an iterator
+type IterG[T any] struct {
+ tr *BTreeG[T]
+ mut bool
+ locked bool
+ seeked bool
+ atstart bool
+ atend bool
+ stack []iterStackItemG[T]
+ item T
+}
+
+type iterStackItemG[T any] struct {
+ n *node[T]
+ i int
+}
+
+// Iter returns a read-only iterator.
+// The Release method must be called finished with iterator.
+func (tr *BTreeG[T]) Iter() IterG[T] {
+ return tr.iter(false)
+}
+
+func (tr *BTreeG[T]) IterMut() IterG[T] {
+ return tr.iter(true)
+}
+
+// Seek to item greater-or-equal-to key.
+// Returns false if there was no item found.
+func (iter *IterG[T]) Seek(key T) bool {
+ if iter.tr == nil {
+ return false
+ }
+ iter.seeked = true
+ iter.stack = iter.stack[:0]
+ if iter.tr.root == nil {
+ return false
+ }
+ n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
+ for {
+ i, found := iter.tr.find(n, key, nil, 0)
+ iter.stack = append(iter.stack, iterStackItemG[T]{n, i})
+ if found {
+ iter.item = n.items[i]
+ return true
+ }
+ if n.leaf() {
+ iter.stack[len(iter.stack)-1].i--
+ return iter.Next()
+ }
+ n = iter.tr.isoLoad(&(*n.children)[i], iter.mut)
+ }
+}
+
+// First moves iterator to first item in tree.
+// Returns false if the tree is empty.
+func (iter *IterG[T]) First() bool {
+ if iter.tr == nil {
+ return false
+ }
+ iter.atend = false
+ iter.atstart = false
+ iter.seeked = true
+ iter.stack = iter.stack[:0]
+ if iter.tr.root == nil {
+ return false
+ }
+ n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
+ for {
+ iter.stack = append(iter.stack, iterStackItemG[T]{n, 0})
+ if n.leaf() {
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Last moves iterator to last item in tree.
+// Returns false if the tree is empty.
+func (iter *IterG[T]) Last() bool {
+ if iter.tr == nil {
+ return false
+ }
+ iter.seeked = true
+ iter.stack = iter.stack[:0]
+ if iter.tr.root == nil {
+ return false
+ }
+ n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
+ for {
+ iter.stack = append(iter.stack, iterStackItemG[T]{n, len(n.items)})
+ if n.leaf() {
+ iter.stack[len(iter.stack)-1].i--
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Release the iterator.
+func (iter *IterG[T]) Release() {
+ if iter.tr == nil {
+ return
+ }
+ if iter.locked {
+ iter.tr.unlock(iter.mut)
+ iter.locked = false
+ }
+ iter.stack = nil
+ iter.tr = nil
+}
+
+// Next moves iterator to the next item in iterator.
+// Returns false if the tree is empty or the iterator is at the end of
+// the tree.
+func (iter *IterG[T]) Next() bool {
+ if iter.tr == nil {
+ return false
+ }
+ if !iter.seeked {
+ return iter.First()
+ }
+ if len(iter.stack) == 0 {
+ if iter.atstart {
+ return iter.First() && iter.Next()
+ }
+ return false
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ s.i++
+ if s.n.leaf() {
+ if s.i == len(s.n.items) {
+ for {
+ iter.stack = iter.stack[:len(iter.stack)-1]
+ if len(iter.stack) == 0 {
+ iter.atend = true
+ return false
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ if s.i < len(s.n.items) {
+ break
+ }
+ }
+ }
+ } else {
+ n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
+ for {
+ iter.stack = append(iter.stack, iterStackItemG[T]{n, 0})
+ if n.leaf() {
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
+ }
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Prev moves iterator to the previous item in iterator.
+// Returns false if the tree is empty or the iterator is at the beginning of
+// the tree.
+func (iter *IterG[T]) Prev() bool {
+ if iter.tr == nil {
+ return false
+ }
+ if !iter.seeked {
+ return false
+ }
+ if len(iter.stack) == 0 {
+ if iter.atend {
+ return iter.Last() && iter.Prev()
+ }
+ return false
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ if s.n.leaf() {
+ s.i--
+ if s.i == -1 {
+ for {
+ iter.stack = iter.stack[:len(iter.stack)-1]
+ if len(iter.stack) == 0 {
+ iter.atstart = true
+ return false
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ s.i--
+ if s.i > -1 {
+ break
+ }
+ }
+ }
+ } else {
+ n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
+ for {
+ iter.stack = append(iter.stack, iterStackItemG[T]{n, len(n.items)})
+ if n.leaf() {
+ iter.stack[len(iter.stack)-1].i--
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
+ }
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Item returns the current iterator item.
+func (iter *IterG[T]) Item() T {
+ return iter.item
+}
+
+// Items returns all the items in order.
+func (tr *BTreeG[T]) Items() []T {
+ return tr.items(false)
+}
+
+func (tr *BTreeG[T]) ItemsMut() []T {
+ return tr.items(true)
+}
+
+// Clear will delete all items.
+func (tr *BTreeG[T]) Clear() {
+ if tr.lock(true) {
+ defer tr.unlock(true)
+ }
+ tr.root = nil
+ tr.count = 0
+}
From 22c370445e1ab8069d5c3fced61d8a000d9ae017 Mon Sep 17 00:00:00 2001
From: a
Date: Sat, 24 Dec 2022 15:02:47 -0600
Subject: [PATCH 2/4] missed a few
---
btreeg.go | 29 +----------------------------
btreeg_impl.go | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/btreeg.go b/btreeg.go
index fa65073..c8e1b5a 100644
--- a/btreeg.go
+++ b/btreeg.go
@@ -90,16 +90,6 @@ func (tr *BTreeG[T]) ScanMut(iter func(item T) bool) {
tr.scan(iter, true)
}
-func (tr *BTreeG[T]) scan(iter func(item T) bool, mut bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return
- }
- tr.nodeScan(&tr.root, iter, mut)
-}
-
// Get a value for key
func (tr *BTreeG[T]) Get(key T) (T, bool) {
return tr.getHint(key, nil, false)
@@ -154,15 +144,6 @@ func (tr *BTreeG[T]) Reverse(iter func(item T) bool) {
func (tr *BTreeG[T]) ReverseMut(iter func(item T) bool) {
tr.reverse(iter, true)
}
-func (tr *BTreeG[T]) reverse(iter func(item T) bool, mut bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return
- }
- tr.nodeReverse(&tr.root, iter, mut)
-}
// Descend the tree within the range [pivot, first]
// Pass nil for pivot to scan all item in descending order
@@ -173,15 +154,6 @@ func (tr *BTreeG[T]) Descend(pivot T, iter func(item T) bool) {
func (tr *BTreeG[T]) DescendMut(pivot T, iter func(item T) bool) {
tr.descend(pivot, iter, true)
}
-func (tr *BTreeG[T]) descend(pivot T, iter func(item T) bool, mut bool) {
- if tr.lock(mut) {
- defer tr.unlock(mut)
- }
- if tr.root == nil {
- return
- }
- tr.nodeDescend(&tr.root, pivot, nil, 0, iter, mut)
-}
// Load is for bulk loading pre-sorted items
func (tr *BTreeG[T]) Load(item T) (T, bool) {
@@ -415,6 +387,7 @@ func (tr *BTreeG[T]) Height() int {
func (tr *BTreeG[T]) Walk(iter func(item []T) bool) {
tr.walk(iter, false)
}
+
func (tr *BTreeG[T]) WalkMut(iter func(item []T) bool) {
tr.walk(iter, true)
}
diff --git a/btreeg_impl.go b/btreeg_impl.go
index ee36a98..bebecd5 100644
--- a/btreeg_impl.go
+++ b/btreeg_impl.go
@@ -263,6 +263,16 @@ func (tr *BTreeG[T]) nodeSet(cn **node[T], item T,
return prev, replaced, false
}
+func (tr *BTreeG[T]) scan(iter func(item T) bool, mut bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return
+ }
+ tr.nodeScan(&tr.root, iter, mut)
+}
+
func (tr *BTreeG[T]) nodeScan(cn **node[T], iter func(item T) bool, mut bool,
) bool {
n := tr.isoLoad(cn, mut)
@@ -500,6 +510,16 @@ func (tr *BTreeG[T]) nodeAscend(cn **node[T], pivot T, hint *PathHint,
return true
}
+func (tr *BTreeG[T]) reverse(iter func(item T) bool, mut bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return
+ }
+ tr.nodeReverse(&tr.root, iter, mut)
+}
+
func (tr *BTreeG[T]) nodeReverse(cn **node[T], iter func(item T) bool, mut bool,
) bool {
n := tr.isoLoad(cn, mut)
@@ -525,6 +545,16 @@ func (tr *BTreeG[T]) nodeReverse(cn **node[T], iter func(item T) bool, mut bool,
return true
}
+func (tr *BTreeG[T]) descend(pivot T, iter func(item T) bool, mut bool) {
+ if tr.lock(mut) {
+ defer tr.unlock(mut)
+ }
+ if tr.root == nil {
+ return
+ }
+ tr.nodeDescend(&tr.root, pivot, nil, 0, iter, mut)
+}
+
func (tr *BTreeG[T]) nodeDescend(cn **node[T], pivot T, hint *PathHint,
depth int, iter func(item T) bool, mut bool,
) bool {
From fd3315040f0c58d78e7950014ace0ce2802b4fd0 Mon Sep 17 00:00:00 2001
From: a
Date: Sat, 24 Dec 2022 15:05:05 -0600
Subject: [PATCH 3/4] reorder
---
btreeg_deprecated.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/btreeg_deprecated.go b/btreeg_deprecated.go
index 72cfd59..2e562a7 100644
--- a/btreeg_deprecated.go
+++ b/btreeg_deprecated.go
@@ -7,6 +7,10 @@ type Generic[T any] struct {
*BTreeG[T]
}
+func (tr *Generic[T]) Copy() *Generic[T] {
+ return &Generic[T]{tr.BTreeG.Copy()}
+}
+
// NewGeneric returns a generic BTree
//
// Deprecated: use NewBTreeG
@@ -21,7 +25,3 @@ func NewGenericOptions[T any](less func(a, b T) bool, opts Options,
) *Generic[T] {
return &Generic[T]{NewBTreeGOptions(less, opts)}
}
-
-func (tr *Generic[T]) Copy() *Generic[T] {
- return &Generic[T]{tr.BTreeG.Copy()}
-}
From 0e0063bd5c79e7a369d674edaa9bed5b28feaed0 Mon Sep 17 00:00:00 2001
From: a
Date: Sat, 24 Dec 2022 15:12:17 -0600
Subject: [PATCH 4/4] do map
---
map.go | 797 ----------------------------------------------------
map_impl.go | 599 +++++++++++++++++++++++++++++++++++++++
map_iter.go | 202 +++++++++++++
3 files changed, 801 insertions(+), 797 deletions(-)
create mode 100644 map_impl.go
create mode 100644 map_iter.go
diff --git a/map.go b/map.go
index a4d7c04..be5ce1f 100644
--- a/map.go
+++ b/map.go
@@ -3,47 +3,6 @@
// license that can be found in the LICENSE file.
package btree
-import "sync/atomic"
-
-type ordered interface {
- ~int | ~int8 | ~int16 | ~int32 | ~int64 |
- ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
- ~float32 | ~float64 | ~string
-}
-
-type copier[T any] interface {
- Copy() T
-}
-
-type isoCopier[T any] interface {
- IsoCopy() T
-}
-
-func degreeToMinMax(deg int) (min, max int) {
- if deg <= 0 {
- deg = 32
- } else if deg == 1 {
- deg = 2 // must have at least 2
- }
- max = deg*2 - 1 // max items per node. max children is +1
- min = max / 2
- return min, max
-}
-
-var gisoid uint64
-
-func newIsoID() uint64 {
- return atomic.AddUint64(&gisoid, 1)
-}
-
-type mapPair[K ordered, V any] struct {
- // The `value` field should be before the `key` field because doing so
- // allows for the Go compiler to optimize away the `value` field when
- // it's a `struct{}`, which is the case for `btree.Set`.
- value V
- key K
-}
-
type Map[K ordered, V any] struct {
isoid uint64
root *mapNode[K, V]
@@ -68,40 +27,6 @@ type mapNode[K ordered, V any] struct {
children *[]*mapNode[K, V]
}
-// Copy the node for safe isolation.
-func (tr *Map[K, V]) copy(n *mapNode[K, V]) *mapNode[K, V] {
- n2 := new(mapNode[K, V])
- n2.isoid = tr.isoid
- n2.count = n.count
- n2.items = make([]mapPair[K, V], len(n.items), cap(n.items))
- copy(n2.items, n.items)
- if tr.copyValues {
- for i := 0; i < len(n2.items); i++ {
- n2.items[i].value =
- ((interface{})(n2.items[i].value)).(copier[V]).Copy()
- }
- } else if tr.isoCopyValues {
- for i := 0; i < len(n2.items); i++ {
- n2.items[i].value =
- ((interface{})(n2.items[i].value)).(isoCopier[V]).IsoCopy()
- }
- }
- if !n.leaf() {
- n2.children = new([]*mapNode[K, V])
- *n2.children = make([]*mapNode[K, V], len(*n.children), tr.max+1)
- copy(*n2.children, *n.children)
- }
- return n2
-}
-
-// isoLoad loads the provided node and, if needed, performs a copy-on-write.
-func (tr *Map[K, V]) isoLoad(cn **mapNode[K, V], mut bool) *mapNode[K, V] {
- if mut && (*cn).isoid != tr.isoid {
- *cn = tr.copy(*cn)
- }
- return *cn
-}
-
func (tr *Map[K, V]) Copy() *Map[K, V] {
return tr.IsoCopy()
}
@@ -114,47 +39,6 @@ func (tr *Map[K, V]) IsoCopy() *Map[K, V] {
return tr2
}
-func (tr *Map[K, V]) newNode(leaf bool) *mapNode[K, V] {
- n := new(mapNode[K, V])
- n.isoid = tr.isoid
- if !leaf {
- n.children = new([]*mapNode[K, V])
- }
- return n
-}
-
-// leaf returns true if the node is a leaf.
-func (n *mapNode[K, V]) leaf() bool {
- return n.children == nil
-}
-
-func (tr *Map[K, V]) search(n *mapNode[K, V], key K) (index int, found bool) {
- low, high := 0, len(n.items)
- for low < high {
- h := (low + high) / 2
- if !(key < n.items[h].key) {
- low = h + 1
- } else {
- high = h
- }
- }
- if low > 0 && !(n.items[low-1].key < key) {
- return low - 1, true
- }
- return low, false
-}
-
-func (tr *Map[K, V]) init(degree int) {
- if tr.min != 0 {
- return
- }
- tr.min, tr.max = degreeToMinMax(degree)
- _, tr.copyValues = ((interface{})(tr.empty.value)).(copier[V])
- if !tr.copyValues {
- _, tr.isoCopyValues = ((interface{})(tr.empty.value)).(isoCopier[V])
- }
-}
-
// Set or replace a value for a key
func (tr *Map[K, V]) Set(key K, value V) (V, bool) {
item := mapPair[K, V]{key: key, value: value}
@@ -184,77 +68,6 @@ func (tr *Map[K, V]) Set(key K, value V) (V, bool) {
return tr.empty.value, false
}
-func (tr *Map[K, V]) nodeSplit(n *mapNode[K, V],
-) (right *mapNode[K, V], median mapPair[K, V]) {
- i := tr.max / 2
- median = n.items[i]
-
- // right node
- right = tr.newNode(n.leaf())
- right.items = n.items[i+1:]
- if !n.leaf() {
- *right.children = (*n.children)[i+1:]
- }
- right.updateCount()
-
- // left node
- n.items[i] = tr.empty
- n.items = n.items[:i:i]
- if !n.leaf() {
- *n.children = (*n.children)[: i+1 : i+1]
- }
- n.updateCount()
- return right, median
-}
-
-func (n *mapNode[K, V]) updateCount() {
- n.count = len(n.items)
- if !n.leaf() {
- for i := 0; i < len(*n.children); i++ {
- n.count += (*n.children)[i].count
- }
- }
-}
-
-func (tr *Map[K, V]) nodeSet(pn **mapNode[K, V], item mapPair[K, V],
-) (prev V, replaced bool, split bool) {
- n := tr.isoLoad(pn, true)
- i, found := tr.search(n, item.key)
- if found {
- prev = n.items[i].value
- n.items[i] = item
- return prev, true, false
- }
- if n.leaf() {
- if len(n.items) == tr.max {
- return tr.empty.value, false, true
- }
- n.items = append(n.items, tr.empty)
- copy(n.items[i+1:], n.items[i:])
- n.items[i] = item
- n.count++
- return tr.empty.value, false, false
- }
- prev, replaced, split = tr.nodeSet(&(*n.children)[i], item)
- if split {
- if len(n.items) == tr.max {
- return tr.empty.value, false, true
- }
- right, median := tr.nodeSplit((*n.children)[i])
- *n.children = append(*n.children, nil)
- copy((*n.children)[i+1:], (*n.children)[i:])
- (*n.children)[i+1] = right
- n.items = append(n.items, tr.empty)
- copy(n.items[i+1:], n.items[i:])
- n.items[i] = median
- return tr.nodeSet(&n, item)
- }
- if !replaced {
- n.count++
- }
- return prev, replaced, false
-}
-
func (tr *Map[K, V]) Scan(iter func(key K, value V) bool) {
tr.scan(iter, false)
}
@@ -263,36 +76,6 @@ func (tr *Map[K, V]) ScanMut(iter func(key K, value V) bool) {
tr.scan(iter, true)
}
-func (tr *Map[K, V]) scan(iter func(key K, value V) bool, mut bool) {
- if tr.root == nil {
- return
- }
- tr.nodeScan(&tr.root, iter, mut)
-}
-
-func (tr *Map[K, V]) nodeScan(cn **mapNode[K, V],
- iter func(key K, value V) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- for i := 0; i < len(n.items); i++ {
- if !iter(n.items[i].key, n.items[i].value) {
- return false
- }
- }
- return true
- }
- for i := 0; i < len(n.items); i++ {
- if !tr.nodeScan(&(*n.children)[i], iter, mut) {
- return false
- }
- if !iter(n.items[i].key, n.items[i].value) {
- return false
- }
- }
- return tr.nodeScan(&(*n.children)[len(*n.children)-1], iter, mut)
-}
-
// Get a value for key.
func (tr *Map[K, V]) Get(key K) (V, bool) {
return tr.get(key, false)
@@ -313,23 +96,6 @@ func (tr *Map[K, V]) GetMut(key K) (V, bool) {
return tr.get(key, true)
}
-func (tr *Map[K, V]) get(key K, mut bool) (V, bool) {
- if tr.root == nil {
- return tr.empty.value, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- i, found := tr.search(n, key)
- if found {
- return n.items[i].value, true
- }
- if n.leaf() {
- return tr.empty.value, false
- }
- n = tr.isoLoad(&(*n.children)[i], mut)
- }
-}
-
// Len returns the number of items in the tree
func (tr *Map[K, V]) Len() int {
return tr.count
@@ -355,137 +121,6 @@ func (tr *Map[K, V]) Delete(key K) (V, bool) {
return prev.value, true
}
-func (tr *Map[K, V]) delete(pn **mapNode[K, V], max bool, key K,
-) (mapPair[K, V], bool) {
- n := tr.isoLoad(pn, true)
- var i int
- var found bool
- if max {
- i, found = len(n.items)-1, true
- } else {
- i, found = tr.search(n, key)
- }
- if n.leaf() {
- if found {
- // found the items at the leaf, remove it and return.
- prev := n.items[i]
- copy(n.items[i:], n.items[i+1:])
- n.items[len(n.items)-1] = tr.empty
- n.items = n.items[:len(n.items)-1]
- n.count--
- return prev, true
- }
- return tr.empty, false
- }
-
- var prev mapPair[K, V]
- var deleted bool
- if found {
- if max {
- i++
- prev, deleted = tr.delete(&(*n.children)[i], true, tr.empty.key)
- } else {
- prev = n.items[i]
- maxItem, _ := tr.delete(&(*n.children)[i], true, tr.empty.key)
- deleted = true
- n.items[i] = maxItem
- }
- } else {
- prev, deleted = tr.delete(&(*n.children)[i], max, key)
- }
- if !deleted {
- return tr.empty, false
- }
- n.count--
- if len((*n.children)[i].items) < tr.min {
- tr.nodeRebalance(n, i)
- }
- return prev, true
-}
-
-// nodeRebalance rebalances the child nodes following a delete operation.
-// Provide the index of the child node with the number of items that fell
-// below minItems.
-func (tr *Map[K, V]) nodeRebalance(n *mapNode[K, V], i int) {
- if i == len(n.items) {
- i--
- }
-
- // ensure copy-on-write
- left := tr.isoLoad(&(*n.children)[i], true)
- right := tr.isoLoad(&(*n.children)[i+1], true)
-
- if len(left.items)+len(right.items) < tr.max {
- // Merges the left and right children nodes together as a single node
- // that includes (left,item,right), and places the contents into the
- // existing left node. Delete the right node altogether and move the
- // following items and child nodes to the left by one slot.
-
- // merge (left,item,right)
- left.items = append(left.items, n.items[i])
- left.items = append(left.items, right.items...)
- if !left.leaf() {
- *left.children = append(*left.children, *right.children...)
- }
- left.count += right.count + 1
-
- // move the items over one slot
- copy(n.items[i:], n.items[i+1:])
- n.items[len(n.items)-1] = tr.empty
- n.items = n.items[:len(n.items)-1]
-
- // move the children over one slot
- copy((*n.children)[i+1:], (*n.children)[i+2:])
- (*n.children)[len(*n.children)-1] = nil
- (*n.children) = (*n.children)[:len(*n.children)-1]
- } else if len(left.items) > len(right.items) {
- // move left -> right over one slot
-
- // Move the item of the parent node at index into the right-node first
- // slot, and move the left-node last item into the previously moved
- // parent item slot.
- right.items = append(right.items, tr.empty)
- copy(right.items[1:], right.items)
- right.items[0] = n.items[i]
- right.count++
- n.items[i] = left.items[len(left.items)-1]
- left.items[len(left.items)-1] = tr.empty
- left.items = left.items[:len(left.items)-1]
- left.count--
-
- if !left.leaf() {
- // move the left-node last child into the right-node first slot
- *right.children = append(*right.children, nil)
- copy((*right.children)[1:], *right.children)
- (*right.children)[0] = (*left.children)[len(*left.children)-1]
- (*left.children)[len(*left.children)-1] = nil
- (*left.children) = (*left.children)[:len(*left.children)-1]
- left.count -= (*right.children)[0].count
- right.count += (*right.children)[0].count
- }
- } else {
- // move left <- right over one slot
-
- // Same as above but the other direction
- left.items = append(left.items, n.items[i])
- left.count++
- n.items[i] = right.items[0]
- copy(right.items, right.items[1:])
- right.items[len(right.items)-1] = tr.empty
- right.items = right.items[:len(right.items)-1]
- right.count--
-
- if !left.leaf() {
- *left.children = append(*left.children, (*right.children)[0])
- copy(*right.children, (*right.children)[1:])
- (*right.children)[len(*right.children)-1] = nil
- *right.children = (*right.children)[:len(*right.children)-1]
- left.count += (*left.children)[len(*left.children)-1].count
- right.count -= (*left.children)[len(*left.children)-1].count
- }
- }
-}
-
// Ascend the tree within the range [pivot, last]
// Pass nil for pivot to scan all item in ascending order
// Return false to stop iterating
@@ -497,44 +132,6 @@ func (tr *Map[K, V]) AscendMut(pivot K, iter func(key K, value V) bool) {
tr.ascend(pivot, iter, true)
}
-func (tr *Map[K, V]) ascend(pivot K, iter func(key K, value V) bool, mut bool) {
- if tr.root == nil {
- return
- }
- tr.nodeAscend(&tr.root, pivot, iter, mut)
-}
-
-// The return value of this function determines whether we should keep iterating
-// upon this functions return.
-func (tr *Map[K, V]) nodeAscend(cn **mapNode[K, V], pivot K,
- iter func(key K, value V) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- i, found := tr.search(n, pivot)
- if !found {
- if !n.leaf() {
- if !tr.nodeAscend(&(*n.children)[i], pivot, iter, mut) {
- return false
- }
- }
- }
- // We are either in the case that
- // - node is found, we should iterate through it starting at `i`,
- // the index it was located at.
- // - node is not found, and TODO: fill in.
- for ; i < len(n.items); i++ {
- if !iter(n.items[i].key, n.items[i].value) {
- return false
- }
- if !n.leaf() {
- if !tr.nodeScan(&(*n.children)[i+1], iter, mut) {
- return false
- }
- }
- }
- return true
-}
-
func (tr *Map[K, V]) Reverse(iter func(key K, value V) bool) {
tr.reverse(iter, false)
}
@@ -543,39 +140,6 @@ func (tr *Map[K, V]) ReverseMut(iter func(key K, value V) bool) {
tr.reverse(iter, true)
}
-func (tr *Map[K, V]) reverse(iter func(key K, value V) bool, mut bool) {
- if tr.root == nil {
- return
- }
- tr.nodeReverse(&tr.root, iter, mut)
-}
-
-func (tr *Map[K, V]) nodeReverse(cn **mapNode[K, V],
- iter func(key K, value V) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- for i := len(n.items) - 1; i >= 0; i-- {
- if !iter(n.items[i].key, n.items[i].value) {
- return false
- }
- }
- return true
- }
- if !tr.nodeReverse(&(*n.children)[len(*n.children)-1], iter, mut) {
- return false
- }
- for i := len(n.items) - 1; i >= 0; i-- {
- if !iter(n.items[i].key, n.items[i].value) {
- return false
- }
- if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
- return false
- }
- }
- return true
-}
-
// Descend the tree within the range [pivot, first]
// Pass nil for pivot to scan all item in descending order
// Return false to stop iterating
@@ -587,43 +151,6 @@ func (tr *Map[K, V]) DescendMut(pivot K, iter func(key K, value V) bool) {
tr.descend(pivot, iter, true)
}
-func (tr *Map[K, V]) descend(
- pivot K,
- iter func(key K, value V) bool,
- mut bool,
-) {
- if tr.root == nil {
- return
- }
- tr.nodeDescend(&tr.root, pivot, iter, mut)
-}
-
-func (tr *Map[K, V]) nodeDescend(cn **mapNode[K, V], pivot K,
- iter func(key K, value V) bool, mut bool,
-) bool {
- n := tr.isoLoad(cn, mut)
- i, found := tr.search(n, pivot)
- if !found {
- if !n.leaf() {
- if !tr.nodeDescend(&(*n.children)[i], pivot, iter, mut) {
- return false
- }
- }
- i--
- }
- for ; i >= 0; i-- {
- if !iter(n.items[i].key, n.items[i].value) {
- return false
- }
- if !n.leaf() {
- if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
- return false
- }
- }
- }
- return true
-}
-
// Load is for bulk loading pre-sorted items
func (tr *Map[K, V]) Load(key K, value V) (V, bool) {
item := mapPair[K, V]{key: key, value: value}
@@ -667,20 +194,6 @@ func (tr *Map[K, V]) MinMut() (K, V, bool) {
return tr.minMut(true)
}
-func (tr *Map[K, V]) minMut(mut bool) (key K, value V, ok bool) {
- if tr.root == nil {
- return key, value, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- if n.leaf() {
- item := n.items[0]
- return item.key, item.value, true
- }
- n = tr.isoLoad(&(*n.children)[0], mut)
- }
-}
-
// Max returns the maximum item in tree.
// Returns nil if the tree has no items.
func (tr *Map[K, V]) Max() (K, V, bool) {
@@ -691,20 +204,6 @@ func (tr *Map[K, V]) MaxMut() (K, V, bool) {
return tr.maxMut(true)
}
-func (tr *Map[K, V]) maxMut(mut bool) (K, V, bool) {
- if tr.root == nil {
- return tr.empty.key, tr.empty.value, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- if n.leaf() {
- item := n.items[len(n.items)-1]
- return item.key, item.value, true
- }
- n = tr.isoLoad(&(*n.children)[len(*n.children)-1], mut)
- }
-}
-
// PopMin removes the minimum item in tree and returns it.
// Returns nil if the tree has no items.
func (tr *Map[K, V]) PopMin() (K, V, bool) {
@@ -798,28 +297,6 @@ func (tr *Map[K, V]) GetAtMut(index int) (K, V, bool) {
return tr.getAt(index, true)
}
-func (tr *Map[K, V]) getAt(index int, mut bool) (K, V, bool) {
- if tr.root == nil || index < 0 || index >= tr.count {
- return tr.empty.key, tr.empty.value, false
- }
- n := tr.isoLoad(&tr.root, mut)
- for {
- if n.leaf() {
- return n.items[index].key, n.items[index].value, true
- }
- i := 0
- for ; i < len(n.items); i++ {
- if index < (*n.children)[i].count {
- break
- } else if index == (*n.children)[i].count {
- return n.items[i].key, n.items[i].value, true
- }
- index -= (*n.children)[i].count + 1
- }
- n = tr.isoLoad(&(*n.children)[i], mut)
- }
-}
-
// DeleteAt deletes the item at index.
// Return nil if the tree is empty or the index is out of bounds.
func (tr *Map[K, V]) DeleteAt(index int) (K, V, bool) {
@@ -895,22 +372,6 @@ func (tr *Map[K, V]) Height() int {
return height
}
-// MapIter represents an iterator for btree.Map
-type MapIter[K ordered, V any] struct {
- tr *Map[K, V]
- mut bool
- seeked bool
- atstart bool
- atend bool
- stack []mapIterStackItem[K, V]
- item mapPair[K, V]
-}
-
-type mapIterStackItem[K ordered, V any] struct {
- n *mapNode[K, V]
- i int
-}
-
// Iter returns a read-only iterator.
func (tr *Map[K, V]) Iter() MapIter[K, V] {
return tr.iter(false)
@@ -920,198 +381,6 @@ func (tr *Map[K, V]) IterMut() MapIter[K, V] {
return tr.iter(true)
}
-func (tr *Map[K, V]) iter(mut bool) MapIter[K, V] {
- var iter MapIter[K, V]
- iter.tr = tr
- iter.mut = mut
- return iter
-}
-
-// Seek to item greater-or-equal-to key.
-// Returns false if there was no item found.
-func (iter *MapIter[K, V]) Seek(key K) bool {
- if iter.tr == nil {
- return false
- }
- iter.seeked = true
- iter.stack = iter.stack[:0]
- if iter.tr.root == nil {
- return false
- }
- n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
- for {
- i, found := iter.tr.search(n, key)
- iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, i})
- if found {
- iter.item = n.items[i]
- return true
- }
- if n.leaf() {
- iter.stack[len(iter.stack)-1].i--
- return iter.Next()
- }
- n = iter.tr.isoLoad(&(*n.children)[i], iter.mut)
- }
-}
-
-// First moves iterator to first item in tree.
-// Returns false if the tree is empty.
-func (iter *MapIter[K, V]) First() bool {
- if iter.tr == nil {
- return false
- }
- iter.atend = false
- iter.atstart = false
- iter.seeked = true
- iter.stack = iter.stack[:0]
- if iter.tr.root == nil {
- return false
- }
- n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
- for {
- iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, 0})
- if n.leaf() {
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
- }
- s := &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Last moves iterator to last item in tree.
-// Returns false if the tree is empty.
-func (iter *MapIter[K, V]) Last() bool {
- if iter.tr == nil {
- return false
- }
- iter.seeked = true
- iter.stack = iter.stack[:0]
- if iter.tr.root == nil {
- return false
- }
- n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
- for {
- iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, len(n.items)})
- if n.leaf() {
- iter.stack[len(iter.stack)-1].i--
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
- }
- s := &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Next moves iterator to the next item in iterator.
-// Returns false if the tree is empty or the iterator is at the end of
-// the tree.
-func (iter *MapIter[K, V]) Next() bool {
- if iter.tr == nil {
- return false
- }
- if !iter.seeked {
- return iter.First()
- }
- if len(iter.stack) == 0 {
- if iter.atstart {
- return iter.First() && iter.Next()
- }
- return false
- }
- s := &iter.stack[len(iter.stack)-1]
- s.i++
- if s.n.leaf() {
- if s.i == len(s.n.items) {
- for {
- iter.stack = iter.stack[:len(iter.stack)-1]
- if len(iter.stack) == 0 {
- iter.atend = true
- return false
- }
- s = &iter.stack[len(iter.stack)-1]
- if s.i < len(s.n.items) {
- break
- }
- }
- }
- } else {
- n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
- for {
- iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, 0})
- if n.leaf() {
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
- }
- }
- s = &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Prev moves iterator to the previous item in iterator.
-// Returns false if the tree is empty or the iterator is at the beginning of
-// the tree.
-func (iter *MapIter[K, V]) Prev() bool {
- if iter.tr == nil {
- return false
- }
- if !iter.seeked {
- return false
- }
- if len(iter.stack) == 0 {
- if iter.atend {
- return iter.Last() && iter.Prev()
- }
- return false
- }
- s := &iter.stack[len(iter.stack)-1]
- if s.n.leaf() {
- s.i--
- if s.i == -1 {
- for {
- iter.stack = iter.stack[:len(iter.stack)-1]
- if len(iter.stack) == 0 {
- iter.atstart = true
- return false
- }
- s = &iter.stack[len(iter.stack)-1]
- s.i--
- if s.i > -1 {
- break
- }
- }
- }
- } else {
- n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
- for {
- iter.stack = append(iter.stack,
- mapIterStackItem[K, V]{n, len(n.items)})
- if n.leaf() {
- iter.stack[len(iter.stack)-1].i--
- break
- }
- n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
- }
- }
- s = &iter.stack[len(iter.stack)-1]
- iter.item = s.n.items[s.i]
- return true
-}
-
-// Key returns the current iterator item key.
-func (iter *MapIter[K, V]) Key() K {
- return iter.item.key
-}
-
-// Value returns the current iterator item value.
-func (iter *MapIter[K, V]) Value() V {
- return iter.item.value
-}
-
// Values returns all the values in order.
func (tr *Map[K, V]) Values() []V {
return tr.values(false)
@@ -1121,29 +390,6 @@ func (tr *Map[K, V]) ValuesMut() []V {
return tr.values(true)
}
-func (tr *Map[K, V]) values(mut bool) []V {
- values := make([]V, 0, tr.Len())
- if tr.root != nil {
- values = tr.nodeValues(&tr.root, values, mut)
- }
- return values
-}
-
-func (tr *Map[K, V]) nodeValues(cn **mapNode[K, V], values []V, mut bool) []V {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- for i := 0; i < len(n.items); i++ {
- values = append(values, n.items[i].value)
- }
- return values
- }
- for i := 0; i < len(n.items); i++ {
- values = tr.nodeValues(&(*n.children)[i], values, mut)
- values = append(values, n.items[i].value)
- }
- return tr.nodeValues(&(*n.children)[len(*n.children)-1], values, mut)
-}
-
// Keys returns all the keys in order.
func (tr *Map[K, V]) Keys() []K {
keys := make([]K, 0, tr.Len())
@@ -1153,20 +399,6 @@ func (tr *Map[K, V]) Keys() []K {
return keys
}
-func (n *mapNode[K, V]) keys(keys []K) []K {
- if n.leaf() {
- for i := 0; i < len(n.items); i++ {
- keys = append(keys, n.items[i].key)
- }
- return keys
- }
- for i := 0; i < len(n.items); i++ {
- keys = (*n.children)[i].keys(keys)
- keys = append(keys, n.items[i].key)
- }
- return (*n.children)[len(*n.children)-1].keys(keys)
-}
-
// KeyValues returns all the keys and values in order.
func (tr *Map[K, V]) KeyValues() ([]K, []V) {
return tr.keyValues(false)
@@ -1176,35 +408,6 @@ func (tr *Map[K, V]) KeyValuesMut() ([]K, []V) {
return tr.keyValues(true)
}
-func (tr *Map[K, V]) keyValues(mut bool) ([]K, []V) {
- keys := make([]K, 0, tr.Len())
- values := make([]V, 0, tr.Len())
- if tr.root != nil {
- keys, values = tr.nodeKeyValues(&tr.root, keys, values, mut)
- }
- return keys, values
-}
-
-func (tr *Map[K, V]) nodeKeyValues(cn **mapNode[K, V], keys []K, values []V,
- mut bool,
-) ([]K, []V) {
- n := tr.isoLoad(cn, mut)
- if n.leaf() {
- for i := 0; i < len(n.items); i++ {
- keys = append(keys, n.items[i].key)
- values = append(values, n.items[i].value)
- }
- return keys, values
- }
- for i := 0; i < len(n.items); i++ {
- keys, values = tr.nodeKeyValues(&(*n.children)[i], keys, values, mut)
- keys = append(keys, n.items[i].key)
- values = append(values, n.items[i].value)
- }
- return tr.nodeKeyValues(&(*n.children)[len(*n.children)-1], keys, values,
- mut)
-}
-
// Clear will delete all items.
func (tr *Map[K, V]) Clear() {
tr.count = 0
diff --git a/map_impl.go b/map_impl.go
new file mode 100644
index 0000000..b37734b
--- /dev/null
+++ b/map_impl.go
@@ -0,0 +1,599 @@
+package btree
+
+import "sync/atomic"
+
+type ordered interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
+ ~float32 | ~float64 | ~string
+}
+
+type copier[T any] interface {
+ Copy() T
+}
+
+type isoCopier[T any] interface {
+ IsoCopy() T
+}
+
+func degreeToMinMax(deg int) (min, max int) {
+ if deg <= 0 {
+ deg = 32
+ } else if deg == 1 {
+ deg = 2 // must have at least 2
+ }
+ max = deg*2 - 1 // max items per node. max children is +1
+ min = max / 2
+ return min, max
+}
+
+var gisoid uint64
+
+func newIsoID() uint64 {
+ return atomic.AddUint64(&gisoid, 1)
+}
+
+type mapPair[K ordered, V any] struct {
+ // The `value` field should be before the `key` field because doing so
+ // allows for the Go compiler to optimize away the `value` field when
+ // it's a `struct{}`, which is the case for `btree.Set`.
+ value V
+ key K
+}
+
+// Copy the node for safe isolation.
+func (tr *Map[K, V]) copy(n *mapNode[K, V]) *mapNode[K, V] {
+ n2 := new(mapNode[K, V])
+ n2.isoid = tr.isoid
+ n2.count = n.count
+ n2.items = make([]mapPair[K, V], len(n.items), cap(n.items))
+ copy(n2.items, n.items)
+ if tr.copyValues {
+ for i := 0; i < len(n2.items); i++ {
+ n2.items[i].value =
+ ((interface{})(n2.items[i].value)).(copier[V]).Copy()
+ }
+ } else if tr.isoCopyValues {
+ for i := 0; i < len(n2.items); i++ {
+ n2.items[i].value =
+ ((interface{})(n2.items[i].value)).(isoCopier[V]).IsoCopy()
+ }
+ }
+ if !n.leaf() {
+ n2.children = new([]*mapNode[K, V])
+ *n2.children = make([]*mapNode[K, V], len(*n.children), tr.max+1)
+ copy(*n2.children, *n.children)
+ }
+ return n2
+}
+
+// isoLoad loads the provided node and, if needed, performs a copy-on-write.
+func (tr *Map[K, V]) isoLoad(cn **mapNode[K, V], mut bool) *mapNode[K, V] {
+ if mut && (*cn).isoid != tr.isoid {
+ *cn = tr.copy(*cn)
+ }
+ return *cn
+}
+
+func (tr *Map[K, V]) newNode(leaf bool) *mapNode[K, V] {
+ n := new(mapNode[K, V])
+ n.isoid = tr.isoid
+ if !leaf {
+ n.children = new([]*mapNode[K, V])
+ }
+ return n
+}
+
+// leaf returns true if the node is a leaf.
+func (n *mapNode[K, V]) leaf() bool {
+ return n.children == nil
+}
+
+func (tr *Map[K, V]) search(n *mapNode[K, V], key K) (index int, found bool) {
+ low, high := 0, len(n.items)
+ for low < high {
+ h := (low + high) / 2
+ if !(key < n.items[h].key) {
+ low = h + 1
+ } else {
+ high = h
+ }
+ }
+ if low > 0 && !(n.items[low-1].key < key) {
+ return low - 1, true
+ }
+ return low, false
+}
+
+func (tr *Map[K, V]) init(degree int) {
+ if tr.min != 0 {
+ return
+ }
+ tr.min, tr.max = degreeToMinMax(degree)
+ _, tr.copyValues = ((interface{})(tr.empty.value)).(copier[V])
+ if !tr.copyValues {
+ _, tr.isoCopyValues = ((interface{})(tr.empty.value)).(isoCopier[V])
+ }
+}
+
+func (tr *Map[K, V]) nodeSplit(n *mapNode[K, V],
+) (right *mapNode[K, V], median mapPair[K, V]) {
+ i := tr.max / 2
+ median = n.items[i]
+
+ // right node
+ right = tr.newNode(n.leaf())
+ right.items = n.items[i+1:]
+ if !n.leaf() {
+ *right.children = (*n.children)[i+1:]
+ }
+ right.updateCount()
+
+ // left node
+ n.items[i] = tr.empty
+ n.items = n.items[:i:i]
+ if !n.leaf() {
+ *n.children = (*n.children)[: i+1 : i+1]
+ }
+ n.updateCount()
+ return right, median
+}
+
+func (n *mapNode[K, V]) updateCount() {
+ n.count = len(n.items)
+ if !n.leaf() {
+ for i := 0; i < len(*n.children); i++ {
+ n.count += (*n.children)[i].count
+ }
+ }
+}
+
+func (tr *Map[K, V]) nodeSet(pn **mapNode[K, V], item mapPair[K, V],
+) (prev V, replaced bool, split bool) {
+ n := tr.isoLoad(pn, true)
+ i, found := tr.search(n, item.key)
+ if found {
+ prev = n.items[i].value
+ n.items[i] = item
+ return prev, true, false
+ }
+ if n.leaf() {
+ if len(n.items) == tr.max {
+ return tr.empty.value, false, true
+ }
+ n.items = append(n.items, tr.empty)
+ copy(n.items[i+1:], n.items[i:])
+ n.items[i] = item
+ n.count++
+ return tr.empty.value, false, false
+ }
+ prev, replaced, split = tr.nodeSet(&(*n.children)[i], item)
+ if split {
+ if len(n.items) == tr.max {
+ return tr.empty.value, false, true
+ }
+ right, median := tr.nodeSplit((*n.children)[i])
+ *n.children = append(*n.children, nil)
+ copy((*n.children)[i+1:], (*n.children)[i:])
+ (*n.children)[i+1] = right
+ n.items = append(n.items, tr.empty)
+ copy(n.items[i+1:], n.items[i:])
+ n.items[i] = median
+ return tr.nodeSet(&n, item)
+ }
+ if !replaced {
+ n.count++
+ }
+ return prev, replaced, false
+}
+
+func (tr *Map[K, V]) scan(iter func(key K, value V) bool, mut bool) {
+ if tr.root == nil {
+ return
+ }
+ tr.nodeScan(&tr.root, iter, mut)
+}
+
+func (tr *Map[K, V]) nodeScan(cn **mapNode[K, V],
+ iter func(key K, value V) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ for i := 0; i < len(n.items); i++ {
+ if !iter(n.items[i].key, n.items[i].value) {
+ return false
+ }
+ }
+ return true
+ }
+ for i := 0; i < len(n.items); i++ {
+ if !tr.nodeScan(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ if !iter(n.items[i].key, n.items[i].value) {
+ return false
+ }
+ }
+ return tr.nodeScan(&(*n.children)[len(*n.children)-1], iter, mut)
+}
+
+func (tr *Map[K, V]) get(key K, mut bool) (V, bool) {
+ if tr.root == nil {
+ return tr.empty.value, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ i, found := tr.search(n, key)
+ if found {
+ return n.items[i].value, true
+ }
+ if n.leaf() {
+ return tr.empty.value, false
+ }
+ n = tr.isoLoad(&(*n.children)[i], mut)
+ }
+}
+
+func (tr *Map[K, V]) delete(pn **mapNode[K, V], max bool, key K,
+) (mapPair[K, V], bool) {
+ n := tr.isoLoad(pn, true)
+ var i int
+ var found bool
+ if max {
+ i, found = len(n.items)-1, true
+ } else {
+ i, found = tr.search(n, key)
+ }
+ if n.leaf() {
+ if found {
+ // found the items at the leaf, remove it and return.
+ prev := n.items[i]
+ copy(n.items[i:], n.items[i+1:])
+ n.items[len(n.items)-1] = tr.empty
+ n.items = n.items[:len(n.items)-1]
+ n.count--
+ return prev, true
+ }
+ return tr.empty, false
+ }
+
+ var prev mapPair[K, V]
+ var deleted bool
+ if found {
+ if max {
+ i++
+ prev, deleted = tr.delete(&(*n.children)[i], true, tr.empty.key)
+ } else {
+ prev = n.items[i]
+ maxItem, _ := tr.delete(&(*n.children)[i], true, tr.empty.key)
+ deleted = true
+ n.items[i] = maxItem
+ }
+ } else {
+ prev, deleted = tr.delete(&(*n.children)[i], max, key)
+ }
+ if !deleted {
+ return tr.empty, false
+ }
+ n.count--
+ if len((*n.children)[i].items) < tr.min {
+ tr.nodeRebalance(n, i)
+ }
+ return prev, true
+}
+
+// nodeRebalance rebalances the child nodes following a delete operation.
+// Provide the index of the child node with the number of items that fell
+// below minItems.
+func (tr *Map[K, V]) nodeRebalance(n *mapNode[K, V], i int) {
+ if i == len(n.items) {
+ i--
+ }
+
+ // ensure copy-on-write
+ left := tr.isoLoad(&(*n.children)[i], true)
+ right := tr.isoLoad(&(*n.children)[i+1], true)
+
+ if len(left.items)+len(right.items) < tr.max {
+ // Merges the left and right children nodes together as a single node
+ // that includes (left,item,right), and places the contents into the
+ // existing left node. Delete the right node altogether and move the
+ // following items and child nodes to the left by one slot.
+
+ // merge (left,item,right)
+ left.items = append(left.items, n.items[i])
+ left.items = append(left.items, right.items...)
+ if !left.leaf() {
+ *left.children = append(*left.children, *right.children...)
+ }
+ left.count += right.count + 1
+
+ // move the items over one slot
+ copy(n.items[i:], n.items[i+1:])
+ n.items[len(n.items)-1] = tr.empty
+ n.items = n.items[:len(n.items)-1]
+
+ // move the children over one slot
+ copy((*n.children)[i+1:], (*n.children)[i+2:])
+ (*n.children)[len(*n.children)-1] = nil
+ (*n.children) = (*n.children)[:len(*n.children)-1]
+ } else if len(left.items) > len(right.items) {
+ // move left -> right over one slot
+
+ // Move the item of the parent node at index into the right-node first
+ // slot, and move the left-node last item into the previously moved
+ // parent item slot.
+ right.items = append(right.items, tr.empty)
+ copy(right.items[1:], right.items)
+ right.items[0] = n.items[i]
+ right.count++
+ n.items[i] = left.items[len(left.items)-1]
+ left.items[len(left.items)-1] = tr.empty
+ left.items = left.items[:len(left.items)-1]
+ left.count--
+
+ if !left.leaf() {
+ // move the left-node last child into the right-node first slot
+ *right.children = append(*right.children, nil)
+ copy((*right.children)[1:], *right.children)
+ (*right.children)[0] = (*left.children)[len(*left.children)-1]
+ (*left.children)[len(*left.children)-1] = nil
+ (*left.children) = (*left.children)[:len(*left.children)-1]
+ left.count -= (*right.children)[0].count
+ right.count += (*right.children)[0].count
+ }
+ } else {
+ // move left <- right over one slot
+
+ // Same as above but the other direction
+ left.items = append(left.items, n.items[i])
+ left.count++
+ n.items[i] = right.items[0]
+ copy(right.items, right.items[1:])
+ right.items[len(right.items)-1] = tr.empty
+ right.items = right.items[:len(right.items)-1]
+ right.count--
+
+ if !left.leaf() {
+ *left.children = append(*left.children, (*right.children)[0])
+ copy(*right.children, (*right.children)[1:])
+ (*right.children)[len(*right.children)-1] = nil
+ *right.children = (*right.children)[:len(*right.children)-1]
+ left.count += (*left.children)[len(*left.children)-1].count
+ right.count -= (*left.children)[len(*left.children)-1].count
+ }
+ }
+}
+
+func (tr *Map[K, V]) ascend(pivot K, iter func(key K, value V) bool, mut bool) {
+ if tr.root == nil {
+ return
+ }
+ tr.nodeAscend(&tr.root, pivot, iter, mut)
+}
+
+// The return value of this function determines whether we should keep iterating
+// upon this functions return.
+func (tr *Map[K, V]) nodeAscend(cn **mapNode[K, V], pivot K,
+ iter func(key K, value V) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ i, found := tr.search(n, pivot)
+ if !found {
+ if !n.leaf() {
+ if !tr.nodeAscend(&(*n.children)[i], pivot, iter, mut) {
+ return false
+ }
+ }
+ }
+ // We are either in the case that
+ // - node is found, we should iterate through it starting at `i`,
+ // the index it was located at.
+ // - node is not found, and TODO: fill in.
+ for ; i < len(n.items); i++ {
+ if !iter(n.items[i].key, n.items[i].value) {
+ return false
+ }
+ if !n.leaf() {
+ if !tr.nodeScan(&(*n.children)[i+1], iter, mut) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (tr *Map[K, V]) reverse(iter func(key K, value V) bool, mut bool) {
+ if tr.root == nil {
+ return
+ }
+ tr.nodeReverse(&tr.root, iter, mut)
+}
+
+func (tr *Map[K, V]) nodeReverse(cn **mapNode[K, V],
+ iter func(key K, value V) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ for i := len(n.items) - 1; i >= 0; i-- {
+ if !iter(n.items[i].key, n.items[i].value) {
+ return false
+ }
+ }
+ return true
+ }
+ if !tr.nodeReverse(&(*n.children)[len(*n.children)-1], iter, mut) {
+ return false
+ }
+ for i := len(n.items) - 1; i >= 0; i-- {
+ if !iter(n.items[i].key, n.items[i].value) {
+ return false
+ }
+ if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ }
+ return true
+}
+
+func (tr *Map[K, V]) descend(
+ pivot K,
+ iter func(key K, value V) bool,
+ mut bool,
+) {
+ if tr.root == nil {
+ return
+ }
+ tr.nodeDescend(&tr.root, pivot, iter, mut)
+}
+
+func (tr *Map[K, V]) nodeDescend(cn **mapNode[K, V], pivot K,
+ iter func(key K, value V) bool, mut bool,
+) bool {
+ n := tr.isoLoad(cn, mut)
+ i, found := tr.search(n, pivot)
+ if !found {
+ if !n.leaf() {
+ if !tr.nodeDescend(&(*n.children)[i], pivot, iter, mut) {
+ return false
+ }
+ }
+ i--
+ }
+ for ; i >= 0; i-- {
+ if !iter(n.items[i].key, n.items[i].value) {
+ return false
+ }
+ if !n.leaf() {
+ if !tr.nodeReverse(&(*n.children)[i], iter, mut) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (tr *Map[K, V]) minMut(mut bool) (key K, value V, ok bool) {
+ if tr.root == nil {
+ return key, value, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ if n.leaf() {
+ item := n.items[0]
+ return item.key, item.value, true
+ }
+ n = tr.isoLoad(&(*n.children)[0], mut)
+ }
+}
+
+func (tr *Map[K, V]) maxMut(mut bool) (K, V, bool) {
+ if tr.root == nil {
+ return tr.empty.key, tr.empty.value, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ if n.leaf() {
+ item := n.items[len(n.items)-1]
+ return item.key, item.value, true
+ }
+ n = tr.isoLoad(&(*n.children)[len(*n.children)-1], mut)
+ }
+}
+
+func (tr *Map[K, V]) getAt(index int, mut bool) (K, V, bool) {
+ if tr.root == nil || index < 0 || index >= tr.count {
+ return tr.empty.key, tr.empty.value, false
+ }
+ n := tr.isoLoad(&tr.root, mut)
+ for {
+ if n.leaf() {
+ return n.items[index].key, n.items[index].value, true
+ }
+ i := 0
+ for ; i < len(n.items); i++ {
+ if index < (*n.children)[i].count {
+ break
+ } else if index == (*n.children)[i].count {
+ return n.items[i].key, n.items[i].value, true
+ }
+ index -= (*n.children)[i].count + 1
+ }
+ n = tr.isoLoad(&(*n.children)[i], mut)
+ }
+}
+
+func (tr *Map[K, V]) values(mut bool) []V {
+ values := make([]V, 0, tr.Len())
+ if tr.root != nil {
+ values = tr.nodeValues(&tr.root, values, mut)
+ }
+ return values
+}
+
+func (tr *Map[K, V]) nodeValues(cn **mapNode[K, V], values []V, mut bool) []V {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ for i := 0; i < len(n.items); i++ {
+ values = append(values, n.items[i].value)
+ }
+ return values
+ }
+ for i := 0; i < len(n.items); i++ {
+ values = tr.nodeValues(&(*n.children)[i], values, mut)
+ values = append(values, n.items[i].value)
+ }
+ return tr.nodeValues(&(*n.children)[len(*n.children)-1], values, mut)
+}
+
+func (n *mapNode[K, V]) keys(keys []K) []K {
+ if n.leaf() {
+ for i := 0; i < len(n.items); i++ {
+ keys = append(keys, n.items[i].key)
+ }
+ return keys
+ }
+ for i := 0; i < len(n.items); i++ {
+ keys = (*n.children)[i].keys(keys)
+ keys = append(keys, n.items[i].key)
+ }
+ return (*n.children)[len(*n.children)-1].keys(keys)
+}
+
+func (tr *Map[K, V]) keyValues(mut bool) ([]K, []V) {
+ keys := make([]K, 0, tr.Len())
+ values := make([]V, 0, tr.Len())
+ if tr.root != nil {
+ keys, values = tr.nodeKeyValues(&tr.root, keys, values, mut)
+ }
+ return keys, values
+}
+
+func (tr *Map[K, V]) nodeKeyValues(cn **mapNode[K, V], keys []K, values []V,
+ mut bool,
+) ([]K, []V) {
+ n := tr.isoLoad(cn, mut)
+ if n.leaf() {
+ for i := 0; i < len(n.items); i++ {
+ keys = append(keys, n.items[i].key)
+ values = append(values, n.items[i].value)
+ }
+ return keys, values
+ }
+ for i := 0; i < len(n.items); i++ {
+ keys, values = tr.nodeKeyValues(&(*n.children)[i], keys, values, mut)
+ keys = append(keys, n.items[i].key)
+ values = append(values, n.items[i].value)
+ }
+ return tr.nodeKeyValues(&(*n.children)[len(*n.children)-1], keys, values,
+ mut)
+}
+
+// iterator
+
+func (tr *Map[K, V]) iter(mut bool) MapIter[K, V] {
+ var iter MapIter[K, V]
+ iter.tr = tr
+ iter.mut = mut
+ return iter
+}
diff --git a/map_iter.go b/map_iter.go
new file mode 100644
index 0000000..c41917f
--- /dev/null
+++ b/map_iter.go
@@ -0,0 +1,202 @@
+package btree
+
+// MapIter represents an iterator for btree.Map
+type MapIter[K ordered, V any] struct {
+ tr *Map[K, V]
+ mut bool
+ seeked bool
+ atstart bool
+ atend bool
+ stack []mapIterStackItem[K, V]
+ item mapPair[K, V]
+}
+
+type mapIterStackItem[K ordered, V any] struct {
+ n *mapNode[K, V]
+ i int
+}
+
+// Seek to item greater-or-equal-to key.
+// Returns false if there was no item found.
+func (iter *MapIter[K, V]) Seek(key K) bool {
+ if iter.tr == nil {
+ return false
+ }
+ iter.seeked = true
+ iter.stack = iter.stack[:0]
+ if iter.tr.root == nil {
+ return false
+ }
+ n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
+ for {
+ i, found := iter.tr.search(n, key)
+ iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, i})
+ if found {
+ iter.item = n.items[i]
+ return true
+ }
+ if n.leaf() {
+ iter.stack[len(iter.stack)-1].i--
+ return iter.Next()
+ }
+ n = iter.tr.isoLoad(&(*n.children)[i], iter.mut)
+ }
+}
+
+// First moves iterator to first item in tree.
+// Returns false if the tree is empty.
+func (iter *MapIter[K, V]) First() bool {
+ if iter.tr == nil {
+ return false
+ }
+ iter.atend = false
+ iter.atstart = false
+ iter.seeked = true
+ iter.stack = iter.stack[:0]
+ if iter.tr.root == nil {
+ return false
+ }
+ n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
+ for {
+ iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, 0})
+ if n.leaf() {
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Last moves iterator to last item in tree.
+// Returns false if the tree is empty.
+func (iter *MapIter[K, V]) Last() bool {
+ if iter.tr == nil {
+ return false
+ }
+ iter.seeked = true
+ iter.stack = iter.stack[:0]
+ if iter.tr.root == nil {
+ return false
+ }
+ n := iter.tr.isoLoad(&iter.tr.root, iter.mut)
+ for {
+ iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, len(n.items)})
+ if n.leaf() {
+ iter.stack[len(iter.stack)-1].i--
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Next moves iterator to the next item in iterator.
+// Returns false if the tree is empty or the iterator is at the end of
+// the tree.
+func (iter *MapIter[K, V]) Next() bool {
+ if iter.tr == nil {
+ return false
+ }
+ if !iter.seeked {
+ return iter.First()
+ }
+ if len(iter.stack) == 0 {
+ if iter.atstart {
+ return iter.First() && iter.Next()
+ }
+ return false
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ s.i++
+ if s.n.leaf() {
+ if s.i == len(s.n.items) {
+ for {
+ iter.stack = iter.stack[:len(iter.stack)-1]
+ if len(iter.stack) == 0 {
+ iter.atend = true
+ return false
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ if s.i < len(s.n.items) {
+ break
+ }
+ }
+ }
+ } else {
+ n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
+ for {
+ iter.stack = append(iter.stack, mapIterStackItem[K, V]{n, 0})
+ if n.leaf() {
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[0], iter.mut)
+ }
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Prev moves iterator to the previous item in iterator.
+// Returns false if the tree is empty or the iterator is at the beginning of
+// the tree.
+func (iter *MapIter[K, V]) Prev() bool {
+ if iter.tr == nil {
+ return false
+ }
+ if !iter.seeked {
+ return false
+ }
+ if len(iter.stack) == 0 {
+ if iter.atend {
+ return iter.Last() && iter.Prev()
+ }
+ return false
+ }
+ s := &iter.stack[len(iter.stack)-1]
+ if s.n.leaf() {
+ s.i--
+ if s.i == -1 {
+ for {
+ iter.stack = iter.stack[:len(iter.stack)-1]
+ if len(iter.stack) == 0 {
+ iter.atstart = true
+ return false
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ s.i--
+ if s.i > -1 {
+ break
+ }
+ }
+ }
+ } else {
+ n := iter.tr.isoLoad(&(*s.n.children)[s.i], iter.mut)
+ for {
+ iter.stack = append(iter.stack,
+ mapIterStackItem[K, V]{n, len(n.items)})
+ if n.leaf() {
+ iter.stack[len(iter.stack)-1].i--
+ break
+ }
+ n = iter.tr.isoLoad(&(*n.children)[len(n.items)], iter.mut)
+ }
+ }
+ s = &iter.stack[len(iter.stack)-1]
+ iter.item = s.n.items[s.i]
+ return true
+}
+
+// Key returns the current iterator item key.
+func (iter *MapIter[K, V]) Key() K {
+ return iter.item.key
+}
+
+// Value returns the current iterator item value.
+func (iter *MapIter[K, V]) Value() V {
+ return iter.item.value
+}