From d23498fd54e376b7f522aef5bdc863e2dd2b6f13 Mon Sep 17 00:00:00 2001 From: langhuihui <178529795@qq.com> Date: Fri, 1 Nov 2024 20:33:36 +0800 Subject: [PATCH] feat: treap --- pkg/util/allocator.go | 486 +++++++++++++++--------------------- pkg/util/allocator_2tree.go | 360 ++++++++++++++++++++++++++ 2 files changed, 568 insertions(+), 278 deletions(-) create mode 100644 pkg/util/allocator_2tree.go diff --git a/pkg/util/allocator.go b/pkg/util/allocator.go index 5d50278..3b90ecc 100644 --- a/pkg/util/allocator.go +++ b/pkg/util/allocator.go @@ -1,18 +1,11 @@ -//go:build !treap +//go:build !twotree package util -const TreeIndexSize = 0 -const TreeIndexOffset = 1 - type ( - Tree struct { - left, right *Block - height int - } Block struct { - Start, End int - trees [2]Tree + Start, End int + parent, left, right *Block } History struct { Malloc bool @@ -20,202 +13,232 @@ type ( Size int } Allocator struct { - pool *Block - sizeTree *Block - offsetTree *Block - Size int - //history []History + pool *Block + sizeTree *Block // Single treap instead of sizeTree/offsetTree + Size int + // history []History } ) -func (t *Tree) deleteLeft(b *Block, treeIndex int) { - t.left = t.left.delete(b, treeIndex) -} - -func (t *Tree) deleteRight(b *Block, treeIndex int) { - t.right = t.right.delete(b, treeIndex) -} - +// Update NewAllocator func NewAllocator(size int) (result *Allocator) { - root := &Block{Start: 0, End: size} result = &Allocator{ - sizeTree: root, - offsetTree: root, - Size: size, + sizeTree: &Block{Start: 0, End: size}, + Size: size, } return } -func compareBySize(a, b *Block) bool { - //if a.Start == b.Start { - // panic("duplicate block") - //} - if sizea, sizeb := a.End-a.Start, b.End-b.Start; sizea != sizeb { - return sizea < sizeb +func (p *Block) rotateDone(x, y *Block, a *Allocator) { + x.parent = p + if p == nil { + a.sizeTree = x + } else if p.left == y { + p.left = x + } else { + p.right = x } - return a.Start < b.Start } -func compareByOffset(a, b *Block) bool { - //if a.Start == b.Start { - // panic("duplicate block") - //} - return a.Start < b.Start +// Add rotation helpers similar to semaRoot +func (x *Block) rotateLeft(a *Allocator) { + p, y, b := x.parent, x.right, x.right.left + y.left, x.parent, x.right = x, y, b + if b != nil { + b.parent = x + } + p.rotateDone(y, x, a) } -var compares = [...]func(a, b *Block) bool{compareBySize, compareByOffset} -var emptyTrees = [2]Tree{} +func (y *Block) rotateRight(a *Allocator) { + p, x, b := y.parent, y.left, y.left.right + x.right, y.parent, y.left = y, x, b + if b != nil { + b.parent = y + } + p.rotateDone(x, y, a) +} -func (b *Block) insert(block *Block, treeIndex int) *Block { +func (b *Block) insert(block *Block, allocator *Allocator) *Block { if b == nil { return block } - if tree := &b.trees[treeIndex]; compares[treeIndex](block, b) { - tree.left = tree.left.insert(block, treeIndex) + + if block.End == block.Start { + panic("empty block") + } + + // Insert as BST using Start value + if block.Start < b.Start { + b.left = b.left.insert(block, allocator) + if b.left != nil { + b.left.parent = b + } } else { - tree.right = tree.right.insert(block, treeIndex) - } - b.updateHeight(treeIndex) - return b.balance(treeIndex) -} - -func (b *Block) getLeftHeight(treeIndex int) int { - return b.trees[treeIndex].left.getHeight(treeIndex) -} - -func (b *Block) getRightHeight(treeIndex int) int { - return b.trees[treeIndex].right.getHeight(treeIndex) -} - -func (b *Block) getHeight(treeIndex int) int { - if b == nil { - return 0 - } - return b.trees[treeIndex].height -} - -func (b *Block) updateHeight(treeIndex int) { - b.trees[treeIndex].height = 1 + max(b.getLeftHeight(treeIndex), b.getRightHeight(treeIndex)) -} - -func (b *Block) balance(treeIndex int) *Block { - if b == nil { - return nil - } - if tree := &b.trees[treeIndex]; b.getLeftHeight(treeIndex)-b.getRightHeight(treeIndex) > 1 { - if tree.left.getRightHeight(treeIndex) > tree.left.getLeftHeight(treeIndex) { - tree.left = tree.left.rotateLeft(treeIndex) + b.right = b.right.insert(block, allocator) + if b.right != nil { + b.right.parent = b } - return b.rotateRight(treeIndex) - } else if b.getRightHeight(treeIndex)-b.getLeftHeight(treeIndex) > 1 { - if tree.right.getLeftHeight(treeIndex) > tree.right.getRightHeight(treeIndex) { - tree.right = tree.right.rotateRight(treeIndex) + } + + // Heapify based on block size (End-Start) + blockSize := block.End - block.Start + nodeSize := b.End - b.Start + + if blockSize < nodeSize { + // Need to rotate up if current node has smaller size + if block == b.left { + b.rotateRight(allocator) + return block + } else if block == b.right { + b.rotateLeft(allocator) + return block } - return b.rotateLeft(treeIndex) } return b } -func (b *Block) rotateLeft(treeIndex int) *Block { - newRoot := b.trees[treeIndex].right - b.trees[treeIndex].right = newRoot.trees[treeIndex].left - newRoot.trees[treeIndex].left = b - b.updateHeight(treeIndex) - newRoot.updateHeight(treeIndex) - return newRoot -} - -func (b *Block) rotateRight(treeIndex int) *Block { - newRoot := b.trees[treeIndex].left - b.trees[treeIndex].left = newRoot.trees[treeIndex].right - newRoot.trees[treeIndex].right = b - b.updateHeight(treeIndex) - newRoot.updateHeight(treeIndex) - return newRoot -} - -func (b *Block) findMin(treeIndex int) *Block { - if left := b.trees[treeIndex].left; left == nil { - return b - } else { - return left.findMin(treeIndex) - } -} - -func (b *Block) delete(block *Block, treeIndex int) *Block { +func (b *Block) find(size int) (block *Block) { if b == nil { return nil } - defer func() { - block.trees[treeIndex] = emptyTrees[treeIndex] - }() - if compareFunc, tree := compares[treeIndex], &b.trees[treeIndex]; b == block { - if tree.left == nil { - return tree.right - } else if tree.right == nil { - return tree.left + + // First check if current block can be used + if blockSize := b.End - b.Start; blockSize >= size { + // If exact match, return this block + if blockSize == size { + return b } - minBlock := tree.right.findMin(treeIndex) - tree.deleteRight(minBlock, treeIndex) - minTree := &minBlock.trees[treeIndex] - minTree.left = tree.left - minTree.right = tree.right - minTree.height = tree.height - return minBlock - } else if compareFunc(block, b) { - tree.deleteLeft(block, treeIndex) - } else { - tree.deleteRight(block, treeIndex) + // Keep searching left for potentially better fit + if left := b.left.find(size); left != nil { + return left + } + // If no better fit found, use this block + return b } - b.updateHeight(treeIndex) - return b.balance(treeIndex) + // If current block too small, only check right side + return b.right.find(size) } -func (a *Allocator) Init(size int) { - a.Size = size - root := a.getBlock(0, size) - a.sizeTree = root - a.offsetTree = root +func (b *Block) Walk(fn func(*Block)) { + if b == nil { + return + } + b.left.Walk(fn) + fn(b) + b.right.Walk(fn) } -func (a *Allocator) Find(size int) (offset int) { - block := a.findAvailableBlock(size) - if block == nil { - return -1 - } - offset = block.Start - return +func (a *Allocator) putBlock(block *Block) { + block.right = nil + block.left = nil + block.parent = a.pool + a.pool = block } func (a *Allocator) Allocate(size int) (offset int) { - //a.history = append(a.history, History{Malloc: true, Size: size}) - block := a.findAvailableBlock(size) + // a.history = append(a.history, History{Malloc: true, Size: size}) + block := a.sizeTree.find(size) if block == nil { return -1 } offset = block.Start - a.deleteSizeTree(block) - a.deleteOffsetTree(block) - if newStart := offset + size; newStart < block.End { - block.Start = newStart - a.insertSizeTree(block) - a.insertOffsetTree(block) - } else { + a.deleteBlock(block) + if blockSize := block.End - block.Start; blockSize == size { + // Remove entire block a.putBlock(block) + } else { + block.Start += size + a.insert(block) + } + return offset +} + +func (a *Allocator) deleteBlock(block *Block) { + // Rotate block down to leaf + for block.left != nil || block.right != nil { + if block.right == nil || (block.left != nil && (block.left.End-block.left.Start) > (block.right.End-block.right.Start)) { + block.rotateRight(a) + } else { + block.rotateLeft(a) + } + } + + // Remove leaf + if p := block.parent; p != nil { + if p.left == block { + p.left = nil + } else { + p.right = nil + } + } else { + a.sizeTree = nil + } +} + +func (a *Allocator) insert(block *Block) { + // a.sizeTree.Walk(func(b *Block) { + // if block.Start >= b.Start && block.Start < b.End { + // out, _ := yaml.Marshal(a.history) + // fmt.Println(string(out)) + // } + // }) + a.sizeTree = a.sizeTree.insert(block, a) + // if a.sizeTree.parent != nil { + // panic("sizeTree parent is not nil") + // } +} + +func (a *Allocator) Free(offset, size int) { + // a.history = append(a.history, History{Malloc: false, Offset: offset, Size: size}) + // Try to merge with adjacent blocks + // Find adjacent blocks + switch left, right := a.findLeftAdjacent(offset), a.findRightAdjacent(offset+size); true { + case left != nil && right != nil: + a.deleteBlock(right) + a.deleteBlock(left) + left.End = right.End + a.insert(left) + a.putBlock(right) + case left == nil && right == nil: + block := a.getBlock(offset, offset+size) + a.insert(block) + case left != nil: + a.deleteBlock(left) + left.End = offset + size + a.insert(left) + case right != nil: + a.deleteBlock(right) + right.Start = offset + a.insert(right) + } +} + +func (a *Allocator) findLeftAdjacent(offset int) (curr *Block) { + curr = a.sizeTree + for curr != nil { + if curr.End == offset { + return + } + if curr.End < offset { + curr = curr.right + } else { + curr = curr.left + } } return } -func (a *Allocator) findAvailableBlock(size int) (lastAvailableBlock *Block) { - block := a.sizeTree - for block != nil { - if bSize := block.End - block.Start; bSize == size { - return block - } else if tree := &block.trees[TreeIndexSize]; size < bSize { - lastAvailableBlock = block - block = tree.left +func (a *Allocator) findRightAdjacent(offset int) (curr *Block) { + curr = a.sizeTree + for curr != nil { + if curr.Start == offset { + return + } + if curr.Start > offset { + curr = curr.left } else { - block = tree.right + curr = curr.right } } return @@ -226,135 +249,42 @@ func (a *Allocator) getBlock(start, end int) *Block { return &Block{Start: start, End: end} } else { block := a.pool - a.pool = block.trees[TreeIndexSize].left - block.trees = emptyTrees + a.pool = block.parent + block.parent = nil block.Start, block.End = start, end return block } } -func (a *Allocator) putBlock(b *Block) { - b.trees = emptyTrees - b.trees[TreeIndexSize].left = a.pool - a.pool = b -} - -func (a *Allocator) Free(offset, size int) { - //a.history = append(a.history, History{Malloc: false, Offset: offset, Size: size}) - switch leftAdjacent, rightAdjacent := a.offsetTree.findLeftAdjacentBlock(offset), a.offsetTree.findRightAdjacentBlock(offset+size); true { - case leftAdjacent != nil && rightAdjacent != nil: - a.deleteOffsetTree(rightAdjacent) - a.deleteSizeTree(rightAdjacent) - a.deleteSizeTree(leftAdjacent) - leftAdjacent.End = rightAdjacent.End - a.insertSizeTree(leftAdjacent) - a.putBlock(rightAdjacent) - case leftAdjacent == nil && rightAdjacent == nil: - block := a.getBlock(offset, offset+size) - a.insertSizeTree(block) - a.insertOffsetTree(block) - case leftAdjacent != nil: - a.deleteSizeTree(leftAdjacent) - leftAdjacent.End = offset + size - a.insertSizeTree(leftAdjacent) - case rightAdjacent != nil: - a.deleteOffsetTree(rightAdjacent) - a.deleteSizeTree(rightAdjacent) - rightAdjacent.Start = offset - a.insertSizeTree(rightAdjacent) - a.insertOffsetTree(rightAdjacent) - } -} - -func (a *Allocator) GetBlocks() (blocks []*Block) { - a.offsetTree.Walk(func(block *Block) { - blocks = append(blocks, block) - }, 1) +func (a *Allocator) GetFreeSize() (size int) { + a.sizeTree.Walk(func(b *Block) { + size += b.End - b.Start + }) return } -func (a *Allocator) GetFreeSize() (ret int) { - a.offsetTree.Walk(func(block *Block) { - ret += block.End - block.Start - }, 1) - return -} - -func (a *Allocator) insertSizeTree(block *Block) { - //if block.End == block.Start { - // panic("empty block") - //} - //a.sizeTree.Walk(func(b *Block) { - // if block.Start >= b.Start && block.Start < b.End { - // out, _ := yaml.Marshal(a.history) - // fmt.Println(string(out)) - // } - //}, 0) - a.sizeTree = a.sizeTree.insert(block, TreeIndexSize) -} - -func (a *Allocator) insertOffsetTree(block *Block) { - //if block.End == block.Start { - // panic("empty block") - //} - //a.offsetTree.Walk(func(b *Block) { - // if block.Start >= b.Start && block.Start < b.End { - // out, _ := yaml.Marshal(a.history) - // fmt.Println(string(out)) - // } - //}, 1) - a.offsetTree = a.offsetTree.insert(block, TreeIndexOffset) -} - -func (a *Allocator) deleteSizeTree(block *Block) { - a.sizeTree = a.sizeTree.delete(block, TreeIndexSize) -} - -func (a *Allocator) deleteOffsetTree(block *Block) { - a.offsetTree = a.offsetTree.delete(block, TreeIndexOffset) -} - -func (b *Block) findLeftAdjacentBlock(offset int) *Block { - for b != nil { - if b.End == offset { - return b - } - if tree := &b.trees[TreeIndexOffset]; b.End > offset { - b = tree.left - } else { - b = tree.right - } - } - return nil -} - -func (b *Block) findRightAdjacentBlock(offset int) *Block { - for b != nil { - if b.Start == offset { - return b - } - if tree := &b.trees[TreeIndexOffset]; b.Start < offset { - b = tree.right - } else { - b = tree.left - } - } - return nil -} - func (a *Allocator) Recycle() { - a.sizeTree.Walk(func(block *Block) { - a.putBlock(block) - }, 0) + a.sizeTree.Walk(a.putBlock) a.sizeTree = nil - a.offsetTree = nil + a.pool = nil } -func (b *Block) Walk(fn func(*Block), index int) { - if b == nil { - return - } - b.trees[index].left.Walk(fn, index) - fn(b) - b.trees[index].right.Walk(fn, index) +func (a *Allocator) Init(size int) { + a.sizeTree = a.getBlock(0, size) + a.Size = size +} + +func (a *Allocator) Find(size int) (offset int) { + block := a.sizeTree.find(size) + if block == nil { + return -1 + } + return block.Start +} + +func (a *Allocator) GetBlocks() (blocks []*Block) { + a.sizeTree.Walk(func(b *Block) { + blocks = append(blocks, b) + }) + return } diff --git a/pkg/util/allocator_2tree.go b/pkg/util/allocator_2tree.go new file mode 100644 index 0000000..0f97ca8 --- /dev/null +++ b/pkg/util/allocator_2tree.go @@ -0,0 +1,360 @@ +//go:build twotree + +package util + +const TreeIndexSize = 0 +const TreeIndexOffset = 1 + +type ( + Tree struct { + left, right *Block + height int + } + Block struct { + Start, End int + trees [2]Tree + } + History struct { + Malloc bool + Offset int + Size int + } + Allocator struct { + pool *Block + sizeTree *Block + offsetTree *Block + Size int + //history []History + } +) + +func (t *Tree) deleteLeft(b *Block, treeIndex int) { + t.left = t.left.delete(b, treeIndex) +} + +func (t *Tree) deleteRight(b *Block, treeIndex int) { + t.right = t.right.delete(b, treeIndex) +} + +func NewAllocator(size int) (result *Allocator) { + root := &Block{Start: 0, End: size} + result = &Allocator{ + sizeTree: root, + offsetTree: root, + Size: size, + } + return +} + +func compareBySize(a, b *Block) bool { + //if a.Start == b.Start { + // panic("duplicate block") + //} + if sizea, sizeb := a.End-a.Start, b.End-b.Start; sizea != sizeb { + return sizea < sizeb + } + return a.Start < b.Start +} + +func compareByOffset(a, b *Block) bool { + //if a.Start == b.Start { + // panic("duplicate block") + //} + return a.Start < b.Start +} + +var compares = [...]func(a, b *Block) bool{compareBySize, compareByOffset} +var emptyTrees = [2]Tree{} + +func (b *Block) insert(block *Block, treeIndex int) *Block { + if b == nil { + return block + } + if tree := &b.trees[treeIndex]; compares[treeIndex](block, b) { + tree.left = tree.left.insert(block, treeIndex) + } else { + tree.right = tree.right.insert(block, treeIndex) + } + b.updateHeight(treeIndex) + return b.balance(treeIndex) +} + +func (b *Block) getLeftHeight(treeIndex int) int { + return b.trees[treeIndex].left.getHeight(treeIndex) +} + +func (b *Block) getRightHeight(treeIndex int) int { + return b.trees[treeIndex].right.getHeight(treeIndex) +} + +func (b *Block) getHeight(treeIndex int) int { + if b == nil { + return 0 + } + return b.trees[treeIndex].height +} + +func (b *Block) updateHeight(treeIndex int) { + b.trees[treeIndex].height = 1 + max(b.getLeftHeight(treeIndex), b.getRightHeight(treeIndex)) +} + +func (b *Block) balance(treeIndex int) *Block { + if b == nil { + return nil + } + if tree := &b.trees[treeIndex]; b.getLeftHeight(treeIndex)-b.getRightHeight(treeIndex) > 1 { + if tree.left.getRightHeight(treeIndex) > tree.left.getLeftHeight(treeIndex) { + tree.left = tree.left.rotateLeft(treeIndex) + } + return b.rotateRight(treeIndex) + } else if b.getRightHeight(treeIndex)-b.getLeftHeight(treeIndex) > 1 { + if tree.right.getLeftHeight(treeIndex) > tree.right.getRightHeight(treeIndex) { + tree.right = tree.right.rotateRight(treeIndex) + } + return b.rotateLeft(treeIndex) + } + return b +} + +func (b *Block) rotateLeft(treeIndex int) *Block { + newRoot := b.trees[treeIndex].right + b.trees[treeIndex].right = newRoot.trees[treeIndex].left + newRoot.trees[treeIndex].left = b + b.updateHeight(treeIndex) + newRoot.updateHeight(treeIndex) + return newRoot +} + +func (b *Block) rotateRight(treeIndex int) *Block { + newRoot := b.trees[treeIndex].left + b.trees[treeIndex].left = newRoot.trees[treeIndex].right + newRoot.trees[treeIndex].right = b + b.updateHeight(treeIndex) + newRoot.updateHeight(treeIndex) + return newRoot +} + +func (b *Block) findMin(treeIndex int) *Block { + if left := b.trees[treeIndex].left; left == nil { + return b + } else { + return left.findMin(treeIndex) + } +} + +func (b *Block) delete(block *Block, treeIndex int) *Block { + if b == nil { + return nil + } + defer func() { + block.trees[treeIndex] = emptyTrees[treeIndex] + }() + if compareFunc, tree := compares[treeIndex], &b.trees[treeIndex]; b == block { + if tree.left == nil { + return tree.right + } else if tree.right == nil { + return tree.left + } + minBlock := tree.right.findMin(treeIndex) + tree.deleteRight(minBlock, treeIndex) + minTree := &minBlock.trees[treeIndex] + minTree.left = tree.left + minTree.right = tree.right + minTree.height = tree.height + return minBlock + } else if compareFunc(block, b) { + tree.deleteLeft(block, treeIndex) + } else { + tree.deleteRight(block, treeIndex) + } + b.updateHeight(treeIndex) + return b.balance(treeIndex) +} + +func (a *Allocator) Init(size int) { + a.Size = size + root := a.getBlock(0, size) + a.sizeTree = root + a.offsetTree = root +} + +func (a *Allocator) Find(size int) (offset int) { + block := a.findAvailableBlock(size) + if block == nil { + return -1 + } + offset = block.Start + return +} + +func (a *Allocator) Allocate(size int) (offset int) { + //a.history = append(a.history, History{Malloc: true, Size: size}) + block := a.findAvailableBlock(size) + if block == nil { + return -1 + } + offset = block.Start + a.deleteSizeTree(block) + a.deleteOffsetTree(block) + if newStart := offset + size; newStart < block.End { + block.Start = newStart + a.insertSizeTree(block) + a.insertOffsetTree(block) + } else { + a.putBlock(block) + } + return +} + +func (a *Allocator) findAvailableBlock(size int) (lastAvailableBlock *Block) { + block := a.sizeTree + for block != nil { + if bSize := block.End - block.Start; bSize == size { + return block + } else if tree := &block.trees[TreeIndexSize]; size < bSize { + lastAvailableBlock = block + block = tree.left + } else { + block = tree.right + } + } + return +} + +func (a *Allocator) getBlock(start, end int) *Block { + if a.pool == nil { + return &Block{Start: start, End: end} + } else { + block := a.pool + a.pool = block.trees[TreeIndexSize].left + block.trees = emptyTrees + block.Start, block.End = start, end + return block + } +} + +func (a *Allocator) putBlock(b *Block) { + b.trees = emptyTrees + b.trees[TreeIndexSize].left = a.pool + a.pool = b +} + +func (a *Allocator) Free(offset, size int) { + //a.history = append(a.history, History{Malloc: false, Offset: offset, Size: size}) + switch leftAdjacent, rightAdjacent := a.offsetTree.findLeftAdjacentBlock(offset), a.offsetTree.findRightAdjacentBlock(offset+size); true { + case leftAdjacent != nil && rightAdjacent != nil: + a.deleteOffsetTree(rightAdjacent) + a.deleteSizeTree(rightAdjacent) + a.deleteSizeTree(leftAdjacent) + leftAdjacent.End = rightAdjacent.End + a.insertSizeTree(leftAdjacent) + a.putBlock(rightAdjacent) + case leftAdjacent == nil && rightAdjacent == nil: + block := a.getBlock(offset, offset+size) + a.insertSizeTree(block) + a.insertOffsetTree(block) + case leftAdjacent != nil: + a.deleteSizeTree(leftAdjacent) + leftAdjacent.End = offset + size + a.insertSizeTree(leftAdjacent) + case rightAdjacent != nil: + a.deleteOffsetTree(rightAdjacent) + a.deleteSizeTree(rightAdjacent) + rightAdjacent.Start = offset + a.insertSizeTree(rightAdjacent) + a.insertOffsetTree(rightAdjacent) + } +} + +func (a *Allocator) GetBlocks() (blocks []*Block) { + a.offsetTree.Walk(func(block *Block) { + blocks = append(blocks, block) + }, 1) + return +} + +func (a *Allocator) GetFreeSize() (ret int) { + a.offsetTree.Walk(func(block *Block) { + ret += block.End - block.Start + }, 1) + return +} + +func (a *Allocator) insertSizeTree(block *Block) { + //if block.End == block.Start { + // panic("empty block") + //} + //a.sizeTree.Walk(func(b *Block) { + // if block.Start >= b.Start && block.Start < b.End { + // out, _ := yaml.Marshal(a.history) + // fmt.Println(string(out)) + // } + //}, 0) + a.sizeTree = a.sizeTree.insert(block, TreeIndexSize) +} + +func (a *Allocator) insertOffsetTree(block *Block) { + //if block.End == block.Start { + // panic("empty block") + //} + //a.offsetTree.Walk(func(b *Block) { + // if block.Start >= b.Start && block.Start < b.End { + // out, _ := yaml.Marshal(a.history) + // fmt.Println(string(out)) + // } + //}, 1) + a.offsetTree = a.offsetTree.insert(block, TreeIndexOffset) +} + +func (a *Allocator) deleteSizeTree(block *Block) { + a.sizeTree = a.sizeTree.delete(block, TreeIndexSize) +} + +func (a *Allocator) deleteOffsetTree(block *Block) { + a.offsetTree = a.offsetTree.delete(block, TreeIndexOffset) +} + +func (b *Block) findLeftAdjacentBlock(offset int) *Block { + for b != nil { + if b.End == offset { + return b + } + if tree := &b.trees[TreeIndexOffset]; b.End > offset { + b = tree.left + } else { + b = tree.right + } + } + return nil +} + +func (b *Block) findRightAdjacentBlock(offset int) *Block { + for b != nil { + if b.Start == offset { + return b + } + if tree := &b.trees[TreeIndexOffset]; b.Start < offset { + b = tree.right + } else { + b = tree.left + } + } + return nil +} + +func (a *Allocator) Recycle() { + a.sizeTree.Walk(func(block *Block) { + a.putBlock(block) + }, 0) + a.sizeTree = nil + a.offsetTree = nil +} + +func (b *Block) Walk(fn func(*Block), index int) { + if b == nil { + return + } + b.trees[index].left.Walk(fn, index) + fn(b) + b.trees[index].right.Walk(fn, index) +}