node.gno

13.29 Kb ยท 518 lines
  1package cow
  2
  3//----------------------------------------
  4// Node
  5
  6// Node represents a node in an AVL tree.
  7type Node struct {
  8	key       string // key is the unique identifier for the node.
  9	value     any    // value is the data stored in the node.
 10	height    int8   // height is the height of the node in the tree.
 11	size      int    // size is the number of nodes in the subtree rooted at this node.
 12	leftNode  *Node  // leftNode is the left child of the node.
 13	rightNode *Node  // rightNode is the right child of the node.
 14}
 15
 16// NewNode creates a new node with the given key and value.
 17func NewNode(key string, value any) *Node {
 18	return &Node{
 19		key:    key,
 20		value:  value,
 21		height: 0,
 22		size:   1,
 23	}
 24}
 25
 26// Size returns the size of the subtree rooted at the node.
 27func (node *Node) Size() int {
 28	if node == nil {
 29		return 0
 30	}
 31	return node.size
 32}
 33
 34// IsLeaf checks if the node is a leaf node (has no children).
 35func (node *Node) IsLeaf() bool {
 36	return node.height == 0
 37}
 38
 39// Key returns the key of the node.
 40func (node *Node) Key() string {
 41	return node.key
 42}
 43
 44// Value returns the value of the node.
 45func (node *Node) Value() any {
 46	return node.value
 47}
 48
 49// _copy creates a copy of the node (excluding value).
 50func (node *Node) _copy() *Node {
 51	if node.height == 0 {
 52		panic("Why are you copying a value node?")
 53	}
 54	return &Node{
 55		key:       node.key,
 56		height:    node.height,
 57		size:      node.size,
 58		leftNode:  node.leftNode,
 59		rightNode: node.rightNode,
 60	}
 61}
 62
 63// Has checks if a node with the given key exists in the subtree rooted at the node.
 64func (node *Node) Has(key string) (has bool) {
 65	if node == nil {
 66		return false
 67	}
 68	if node.key == key {
 69		return true
 70	}
 71	if node.height == 0 {
 72		return false
 73	}
 74	if key < node.key {
 75		return node.getLeftNode().Has(key)
 76	}
 77	return node.getRightNode().Has(key)
 78}
 79
 80// Get searches for a node with the given key in the subtree rooted at the node
 81// and returns its index, value, and whether it exists.
 82func (node *Node) Get(key string) (index int, value any, exists bool) {
 83	if node == nil {
 84		return 0, nil, false
 85	}
 86
 87	if node.height == 0 {
 88		if node.key == key {
 89			return 0, node.value, true
 90		}
 91		if node.key < key {
 92			return 1, nil, false
 93		}
 94		return 0, nil, false
 95	}
 96
 97	if key < node.key {
 98		return node.getLeftNode().Get(key)
 99	}
100
101	rightNode := node.getRightNode()
102	index, value, exists = rightNode.Get(key)
103	index += node.size - rightNode.size
104	return index, value, exists
105}
106
107// GetByIndex retrieves the key-value pair of the node at the given index
108// in the subtree rooted at the node.
109func (node *Node) GetByIndex(index int) (key string, value any) {
110	if node.height == 0 {
111		if index == 0 {
112			return node.key, node.value
113		}
114		panic("GetByIndex asked for invalid index")
115	}
116	// TODO: could improve this by storing the sizes
117	leftNode := node.getLeftNode()
118	if index < leftNode.size {
119		return leftNode.GetByIndex(index)
120	}
121	return node.getRightNode().GetByIndex(index - leftNode.size)
122}
123
124// Set inserts a new node with the given key-value pair into the subtree rooted at the node,
125// and returns the new root of the subtree and whether an existing node was updated.
126//
127// XXX consider a better way to do this... perhaps split Node from Node.
128func (node *Node) Set(key string, value any) (newSelf *Node, updated bool) {
129	if node == nil {
130		return NewNode(key, value), false
131	}
132
133	// Always create a new node for leaf nodes
134	if node.height == 0 {
135		return node.setLeaf(key, value)
136	}
137
138	// Copy the node before modifying
139	newNode := node._copy()
140	if key < node.key {
141		newNode.leftNode, updated = node.getLeftNode().Set(key, value)
142	} else {
143		newNode.rightNode, updated = node.getRightNode().Set(key, value)
144	}
145
146	if !updated {
147		newNode.calcHeightAndSize()
148		return newNode.balance(), updated
149	}
150
151	return newNode, updated
152}
153
154// setLeaf inserts a new leaf node with the given key-value pair into the subtree rooted at the node,
155// and returns the new root of the subtree and whether an existing node was updated.
156func (node *Node) setLeaf(key string, value any) (newSelf *Node, updated bool) {
157	if key == node.key {
158		return NewNode(key, value), true
159	}
160
161	if key < node.key {
162		return &Node{
163			key:       node.key,
164			height:    1,
165			size:      2,
166			leftNode:  NewNode(key, value),
167			rightNode: node,
168		}, false
169	}
170
171	return &Node{
172		key:       key,
173		height:    1,
174		size:      2,
175		leftNode:  node,
176		rightNode: NewNode(key, value),
177	}, false
178}
179
180// Remove deletes the node with the given key from the subtree rooted at the node.
181// returns the new root of the subtree, the new leftmost leaf key (if changed),
182// the removed value and the removal was successful.
183func (node *Node) Remove(key string) (
184	newNode *Node, newKey string, value any, removed bool,
185) {
186	if node == nil {
187		return nil, "", nil, false
188	}
189	if node.height == 0 {
190		if key == node.key {
191			return nil, "", node.value, true
192		}
193		return node, "", nil, false
194	}
195	if key < node.key {
196		var newLeftNode *Node
197		newLeftNode, newKey, value, removed = node.getLeftNode().Remove(key)
198		if !removed {
199			return node, "", value, false
200		}
201		if newLeftNode == nil { // left node held value, was removed
202			return node.rightNode, node.key, value, true
203		}
204		node = node._copy()
205		node.leftNode = newLeftNode
206		node.calcHeightAndSize()
207		node = node.balance()
208		return node, newKey, value, true
209	}
210
211	var newRightNode *Node
212	newRightNode, newKey, value, removed = node.getRightNode().Remove(key)
213	if !removed {
214		return node, "", value, false
215	}
216	if newRightNode == nil { // right node held value, was removed
217		return node.leftNode, "", value, true
218	}
219	node = node._copy()
220	node.rightNode = newRightNode
221	if newKey != "" {
222		node.key = newKey
223	}
224	node.calcHeightAndSize()
225	node = node.balance()
226	return node, "", value, true
227}
228
229// getLeftNode returns the left child of the node.
230func (node *Node) getLeftNode() *Node {
231	return node.leftNode
232}
233
234// getRightNode returns the right child of the node.
235func (node *Node) getRightNode() *Node {
236	return node.rightNode
237}
238
239// rotateRight performs a right rotation on the node and returns the new root.
240// NOTE: overwrites node
241// TODO: optimize balance & rotate
242func (node *Node) rotateRight() *Node {
243	node = node._copy()
244	l := node.getLeftNode()
245	_l := l._copy()
246
247	_lrCached := _l.rightNode
248	_l.rightNode = node
249	node.leftNode = _lrCached
250
251	node.calcHeightAndSize()
252	_l.calcHeightAndSize()
253
254	return _l
255}
256
257// rotateLeft performs a left rotation on the node and returns the new root.
258// NOTE: overwrites node
259// TODO: optimize balance & rotate
260func (node *Node) rotateLeft() *Node {
261	node = node._copy()
262	r := node.getRightNode()
263	_r := r._copy()
264
265	_rlCached := _r.leftNode
266	_r.leftNode = node
267	node.rightNode = _rlCached
268
269	node.calcHeightAndSize()
270	_r.calcHeightAndSize()
271
272	return _r
273}
274
275// calcHeightAndSize updates the height and size of the node based on its children.
276// NOTE: mutates height and size
277func (node *Node) calcHeightAndSize() {
278	node.height = maxInt8(node.getLeftNode().height, node.getRightNode().height) + 1
279	node.size = node.getLeftNode().size + node.getRightNode().size
280}
281
282// calcBalance calculates the balance factor of the node.
283func (node *Node) calcBalance() int {
284	return int(node.getLeftNode().height) - int(node.getRightNode().height)
285}
286
287// balance balances the subtree rooted at the node and returns the new root.
288// NOTE: assumes that node can be modified
289// TODO: optimize balance & rotate
290func (node *Node) balance() (newSelf *Node) {
291	balance := node.calcBalance()
292	if balance >= -1 {
293		return node
294	}
295	if balance > 1 {
296		if node.getLeftNode().calcBalance() >= 0 {
297			// Left Left Case
298			return node.rotateRight()
299		}
300		// Left Right Case
301		left := node.getLeftNode()
302		node.leftNode = left.rotateLeft()
303		return node.rotateRight()
304	}
305
306	if node.getRightNode().calcBalance() <= 0 {
307		// Right Right Case
308		return node.rotateLeft()
309	}
310
311	// Right Left Case
312	right := node.getRightNode()
313	node.rightNode = right.rotateRight()
314	return node.rotateLeft()
315}
316
317// Shortcut for TraverseInRange.
318func (node *Node) Iterate(start, end string, cb func(*Node) bool) bool {
319	return node.TraverseInRange(start, end, true, true, cb)
320}
321
322// Shortcut for TraverseInRange.
323func (node *Node) ReverseIterate(start, end string, cb func(*Node) bool) bool {
324	return node.TraverseInRange(start, end, false, true, cb)
325}
326
327// TraverseInRange traverses all nodes, including inner nodes.
328// Start is inclusive and end is exclusive when ascending,
329// Start and end are inclusive when descending.
330// Empty start and empty end denote no start and no end.
331// If leavesOnly is true, only visit leaf nodes.
332// NOTE: To simulate an exclusive reverse traversal,
333// just append 0x00 to start.
334func (node *Node) TraverseInRange(start, end string, ascending bool, leavesOnly bool, cb func(*Node) bool) bool {
335	if node == nil {
336		return false
337	}
338	afterStart := (start == "" || start < node.key)
339	startOrAfter := (start == "" || start <= node.key)
340	beforeEnd := false
341	if ascending {
342		beforeEnd = (end == "" || node.key < end)
343	} else {
344		beforeEnd = (end == "" || node.key <= end)
345	}
346
347	// Run callback per inner/leaf node.
348	stop := false
349	if (!node.IsLeaf() && !leavesOnly) ||
350		(node.IsLeaf() && startOrAfter && beforeEnd) {
351		stop = cb(node)
352		if stop {
353			return stop
354		}
355	}
356	if node.IsLeaf() {
357		return stop
358	}
359
360	if ascending {
361		// check lower nodes, then higher
362		if afterStart {
363			stop = node.getLeftNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
364		}
365		if stop {
366			return stop
367		}
368		if beforeEnd {
369			stop = node.getRightNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
370		}
371	} else {
372		// check the higher nodes first
373		if beforeEnd {
374			stop = node.getRightNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
375		}
376		if stop {
377			return stop
378		}
379		if afterStart {
380			stop = node.getLeftNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
381		}
382	}
383
384	return stop
385}
386
387// TraverseByOffset traverses all nodes, including inner nodes.
388// A limit of math.MaxInt means no limit.
389func (node *Node) TraverseByOffset(offset, limit int, descending bool, leavesOnly bool, cb func(*Node) bool) bool {
390	if node == nil {
391		return false
392	}
393
394	// fast paths. these happen only if TraverseByOffset is called directly on a leaf.
395	if limit <= 0 || offset >= node.size {
396		return false
397	}
398	if node.IsLeaf() {
399		if offset > 0 {
400			return false
401		}
402		return cb(node)
403	}
404
405	// go to the actual recursive function.
406	return node.traverseByOffset(offset, limit, descending, leavesOnly, cb)
407}
408
409// TraverseByOffset traverses the subtree rooted at the node by offset and limit,
410// in either ascending or descending order, and applies the callback function to each traversed node.
411// If leavesOnly is true, only leaf nodes are visited.
412func (node *Node) traverseByOffset(offset, limit int, descending bool, leavesOnly bool, cb func(*Node) bool) bool {
413	// caller guarantees: offset < node.size; limit > 0.
414	if !leavesOnly {
415		if cb(node) {
416			return true
417		}
418	}
419	first, second := node.getLeftNode(), node.getRightNode()
420	if descending {
421		first, second = second, first
422	}
423	if first.IsLeaf() {
424		// either run or skip, based on offset
425		if offset > 0 {
426			offset--
427		} else {
428			cb(first)
429			limit--
430			if limit <= 0 {
431				return false
432			}
433		}
434	} else {
435		// possible cases:
436		// 1 the offset given skips the first node entirely
437		// 2 the offset skips none or part of the first node, but the limit requires some of the second node.
438		// 3 the offset skips none or part of the first node, and the limit stops our search on the first node.
439		if offset >= first.size {
440			offset -= first.size // 1
441		} else {
442			if first.traverseByOffset(offset, limit, descending, leavesOnly, cb) {
443				return true
444			}
445			// number of leaves which could actually be called from inside
446			delta := first.size - offset
447			offset = 0
448			if delta >= limit {
449				return true // 3
450			}
451			limit -= delta // 2
452		}
453	}
454
455	// because of the caller guarantees and the way we handle the first node,
456	// at this point we know that limit > 0 and there must be some values in
457	// this second node that we include.
458
459	// => if the second node is a leaf, it has to be included.
460	if second.IsLeaf() {
461		return cb(second)
462	}
463	// => if it is not a leaf, it will still be enough to recursively call this
464	// function with the updated offset and limit
465	return second.traverseByOffset(offset, limit, descending, leavesOnly, cb)
466}
467
468// Only used in testing...
469func (node *Node) lmd() *Node {
470	if node.height == 0 {
471		return node
472	}
473	return node.getLeftNode().lmd()
474}
475
476// Only used in testing...
477func (node *Node) rmd() *Node {
478	if node.height == 0 {
479		return node
480	}
481	return node.getRightNode().rmd()
482}
483
484func maxInt8(a, b int8) int8 {
485	if a > b {
486		return a
487	}
488	return b
489}
490
491// Equal compares two nodes for structural equality.
492// WARNING: This is an expensive operation that recursively traverses the entire tree structure.
493// It should only be used in tests or when absolutely necessary.
494func (node *Node) Equal(other *Node) bool {
495	// Handle nil cases
496	if node == nil || other == nil {
497		return node == other
498	}
499
500	// Compare node properties
501	if node.key != other.key ||
502		node.value != other.value ||
503		node.height != other.height ||
504		node.size != other.size {
505		return false
506	}
507
508	// Compare children
509	leftEqual := (node.leftNode == nil && other.leftNode == nil) ||
510		(node.leftNode != nil && other.leftNode != nil && node.leftNode.Equal(other.leftNode))
511	if !leftEqual {
512		return false
513	}
514
515	rightEqual := (node.rightNode == nil && other.rightNode == nil) ||
516		(node.rightNode != nil && other.rightNode != nil && node.rightNode.Equal(other.rightNode))
517	return rightEqual
518}