diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:25:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:25:22 +0000 |
commit | f6ad4dcef54c5ce997a4bad5a6d86de229015700 (patch) | |
tree | 7cfa4e31ace5c2bd95c72b154d15af494b2bcbef /src/cmd/compile/internal/abt/avlint32.go | |
parent | Initial commit. (diff) | |
download | golang-1.22-f6ad4dcef54c5ce997a4bad5a6d86de229015700.tar.xz golang-1.22-f6ad4dcef54c5ce997a4bad5a6d86de229015700.zip |
Adding upstream version 1.22.1.upstream/1.22.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/compile/internal/abt/avlint32.go')
-rw-r--r-- | src/cmd/compile/internal/abt/avlint32.go | 832 |
1 files changed, 832 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/abt/avlint32.go b/src/cmd/compile/internal/abt/avlint32.go new file mode 100644 index 0000000..28c1642 --- /dev/null +++ b/src/cmd/compile/internal/abt/avlint32.go @@ -0,0 +1,832 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package abt + +import ( + "fmt" + "strconv" + "strings" +) + +const ( + LEAF_HEIGHT = 1 + ZERO_HEIGHT = 0 + NOT_KEY32 = int32(-0x80000000) +) + +// T is the exported applicative balanced tree data type. +// A T can be used as a value; updates to one copy of the value +// do not change other copies. +type T struct { + root *node32 + size int +} + +// node32 is the internal tree node data type +type node32 struct { + // Standard conventions hold for left = smaller, right = larger + left, right *node32 + data interface{} + key int32 + height_ int8 +} + +func makeNode(key int32) *node32 { + return &node32{key: key, height_: LEAF_HEIGHT} +} + +// IsEmpty returns true iff t is empty. +func (t *T) IsEmpty() bool { + return t.root == nil +} + +// IsSingle returns true iff t is a singleton (leaf). +func (t *T) IsSingle() bool { + return t.root != nil && t.root.isLeaf() +} + +// VisitInOrder applies f to the key and data pairs in t, +// with keys ordered from smallest to largest. +func (t *T) VisitInOrder(f func(int32, interface{})) { + if t.root == nil { + return + } + t.root.visitInOrder(f) +} + +func (n *node32) nilOrData() interface{} { + if n == nil { + return nil + } + return n.data +} + +func (n *node32) nilOrKeyAndData() (k int32, d interface{}) { + if n == nil { + k = NOT_KEY32 + d = nil + } else { + k = n.key + d = n.data + } + return +} + +func (n *node32) height() int8 { + if n == nil { + return 0 + } + return n.height_ +} + +// Find returns the data associated with x in the tree, or +// nil if x is not in the tree. +func (t *T) Find(x int32) interface{} { + return t.root.find(x).nilOrData() +} + +// Insert either adds x to the tree if x was not previously +// a key in the tree, or updates the data for x in the tree if +// x was already a key in the tree. The previous data associated +// with x is returned, and is nil if x was not previously a +// key in the tree. +func (t *T) Insert(x int32, data interface{}) interface{} { + if x == NOT_KEY32 { + panic("Cannot use sentinel value -0x80000000 as key") + } + n := t.root + var newroot *node32 + var o *node32 + if n == nil { + n = makeNode(x) + newroot = n + } else { + newroot, n, o = n.aInsert(x) + } + var r interface{} + if o != nil { + r = o.data + } else { + t.size++ + } + n.data = data + t.root = newroot + return r +} + +func (t *T) Copy() *T { + u := *t + return &u +} + +func (t *T) Delete(x int32) interface{} { + n := t.root + if n == nil { + return nil + } + d, s := n.aDelete(x) + if d == nil { + return nil + } + t.root = s + t.size-- + return d.data +} + +func (t *T) DeleteMin() (int32, interface{}) { + n := t.root + if n == nil { + return NOT_KEY32, nil + } + d, s := n.aDeleteMin() + if d == nil { + return NOT_KEY32, nil + } + t.root = s + t.size-- + return d.key, d.data +} + +func (t *T) DeleteMax() (int32, interface{}) { + n := t.root + if n == nil { + return NOT_KEY32, nil + } + d, s := n.aDeleteMax() + if d == nil { + return NOT_KEY32, nil + } + t.root = s + t.size-- + return d.key, d.data +} + +func (t *T) Size() int { + return t.size +} + +// Intersection returns the intersection of t and u, where the result +// data for any common keys is given by f(t's data, u's data) -- f need +// not be symmetric. If f returns nil, then the key and data are not +// added to the result. If f itself is nil, then whatever value was +// already present in the smaller set is used. +func (t *T) Intersection(u *T, f func(x, y interface{}) interface{}) *T { + if t.Size() == 0 || u.Size() == 0 { + return &T{} + } + + // For faster execution and less allocation, prefer t smaller, iterate over t. + if t.Size() <= u.Size() { + v := t.Copy() + for it := t.Iterator(); !it.Done(); { + k, d := it.Next() + e := u.Find(k) + if e == nil { + v.Delete(k) + continue + } + if f == nil { + continue + } + if c := f(d, e); c != d { + if c == nil { + v.Delete(k) + } else { + v.Insert(k, c) + } + } + } + return v + } + v := u.Copy() + for it := u.Iterator(); !it.Done(); { + k, e := it.Next() + d := t.Find(k) + if d == nil { + v.Delete(k) + continue + } + if f == nil { + continue + } + if c := f(d, e); c != d { + if c == nil { + v.Delete(k) + } else { + v.Insert(k, c) + } + } + } + + return v +} + +// Union returns the union of t and u, where the result data for any common keys +// is given by f(t's data, u's data) -- f need not be symmetric. If f returns nil, +// then the key and data are not added to the result. If f itself is nil, then +// whatever value was already present in the larger set is used. +func (t *T) Union(u *T, f func(x, y interface{}) interface{}) *T { + if t.Size() == 0 { + return u + } + if u.Size() == 0 { + return t + } + + if t.Size() >= u.Size() { + v := t.Copy() + for it := u.Iterator(); !it.Done(); { + k, e := it.Next() + d := t.Find(k) + if d == nil { + v.Insert(k, e) + continue + } + if f == nil { + continue + } + if c := f(d, e); c != d { + if c == nil { + v.Delete(k) + } else { + v.Insert(k, c) + } + } + } + return v + } + + v := u.Copy() + for it := t.Iterator(); !it.Done(); { + k, d := it.Next() + e := u.Find(k) + if e == nil { + v.Insert(k, d) + continue + } + if f == nil { + continue + } + if c := f(d, e); c != d { + if c == nil { + v.Delete(k) + } else { + v.Insert(k, c) + } + } + } + return v +} + +// Difference returns the difference of t and u, subject to the result +// of f applied to data corresponding to equal keys. If f returns nil +// (or if f is nil) then the key+data are excluded, as usual. If f +// returns not-nil, then that key+data pair is inserted. instead. +func (t *T) Difference(u *T, f func(x, y interface{}) interface{}) *T { + if t.Size() == 0 { + return &T{} + } + if u.Size() == 0 { + return t + } + v := t.Copy() + for it := t.Iterator(); !it.Done(); { + k, d := it.Next() + e := u.Find(k) + if e != nil { + if f == nil { + v.Delete(k) + continue + } + c := f(d, e) + if c == nil { + v.Delete(k) + continue + } + if c != d { + v.Insert(k, c) + } + } + } + return v +} + +func (t *T) Iterator() Iterator { + return Iterator{it: t.root.iterator()} +} + +func (t *T) Equals(u *T) bool { + if t == u { + return true + } + if t.Size() != u.Size() { + return false + } + return t.root.equals(u.root) +} + +func (t *T) String() string { + var b strings.Builder + first := true + for it := t.Iterator(); !it.Done(); { + k, v := it.Next() + if first { + first = false + } else { + b.WriteString("; ") + } + b.WriteString(strconv.FormatInt(int64(k), 10)) + b.WriteString(":") + fmt.Fprint(&b, v) + } + return b.String() +} + +func (t *node32) equals(u *node32) bool { + if t == u { + return true + } + it, iu := t.iterator(), u.iterator() + for !it.done() && !iu.done() { + nt := it.next() + nu := iu.next() + if nt == nu { + continue + } + if nt.key != nu.key { + return false + } + if nt.data != nu.data { + return false + } + } + return it.done() == iu.done() +} + +func (t *T) Equiv(u *T, eqv func(x, y interface{}) bool) bool { + if t == u { + return true + } + if t.Size() != u.Size() { + return false + } + return t.root.equiv(u.root, eqv) +} + +func (t *node32) equiv(u *node32, eqv func(x, y interface{}) bool) bool { + if t == u { + return true + } + it, iu := t.iterator(), u.iterator() + for !it.done() && !iu.done() { + nt := it.next() + nu := iu.next() + if nt == nu { + continue + } + if nt.key != nu.key { + return false + } + if !eqv(nt.data, nu.data) { + return false + } + } + return it.done() == iu.done() +} + +type iterator struct { + parents []*node32 +} + +type Iterator struct { + it iterator +} + +func (it *Iterator) Next() (int32, interface{}) { + x := it.it.next() + if x == nil { + return NOT_KEY32, nil + } + return x.key, x.data +} + +func (it *Iterator) Done() bool { + return len(it.it.parents) == 0 +} + +func (t *node32) iterator() iterator { + if t == nil { + return iterator{} + } + it := iterator{parents: make([]*node32, 0, int(t.height()))} + it.leftmost(t) + return it +} + +func (it *iterator) leftmost(t *node32) { + for t != nil { + it.parents = append(it.parents, t) + t = t.left + } +} + +func (it *iterator) done() bool { + return len(it.parents) == 0 +} + +func (it *iterator) next() *node32 { + l := len(it.parents) + if l == 0 { + return nil + } + x := it.parents[l-1] // return value + if x.right != nil { + it.leftmost(x.right) + return x + } + // discard visited top of parents + l-- + it.parents = it.parents[:l] + y := x // y is known visited/returned + for l > 0 && y == it.parents[l-1].right { + y = it.parents[l-1] + l-- + it.parents = it.parents[:l] + } + + return x +} + +// Min returns the minimum element of t. +// If t is empty, then (NOT_KEY32, nil) is returned. +func (t *T) Min() (k int32, d interface{}) { + return t.root.min().nilOrKeyAndData() +} + +// Max returns the maximum element of t. +// If t is empty, then (NOT_KEY32, nil) is returned. +func (t *T) Max() (k int32, d interface{}) { + return t.root.max().nilOrKeyAndData() +} + +// Glb returns the greatest-lower-bound-exclusive of x and the associated +// data. If x has no glb in the tree, then (NOT_KEY32, nil) is returned. +func (t *T) Glb(x int32) (k int32, d interface{}) { + return t.root.glb(x, false).nilOrKeyAndData() +} + +// GlbEq returns the greatest-lower-bound-inclusive of x and the associated +// data. If x has no glbEQ in the tree, then (NOT_KEY32, nil) is returned. +func (t *T) GlbEq(x int32) (k int32, d interface{}) { + return t.root.glb(x, true).nilOrKeyAndData() +} + +// Lub returns the least-upper-bound-exclusive of x and the associated +// data. If x has no lub in the tree, then (NOT_KEY32, nil) is returned. +func (t *T) Lub(x int32) (k int32, d interface{}) { + return t.root.lub(x, false).nilOrKeyAndData() +} + +// LubEq returns the least-upper-bound-inclusive of x and the associated +// data. If x has no lubEq in the tree, then (NOT_KEY32, nil) is returned. +func (t *T) LubEq(x int32) (k int32, d interface{}) { + return t.root.lub(x, true).nilOrKeyAndData() +} + +func (t *node32) isLeaf() bool { + return t.left == nil && t.right == nil && t.height_ == LEAF_HEIGHT +} + +func (t *node32) visitInOrder(f func(int32, interface{})) { + if t.left != nil { + t.left.visitInOrder(f) + } + f(t.key, t.data) + if t.right != nil { + t.right.visitInOrder(f) + } +} + +func (t *node32) find(key int32) *node32 { + for t != nil { + if key < t.key { + t = t.left + } else if key > t.key { + t = t.right + } else { + return t + } + } + return nil +} + +func (t *node32) min() *node32 { + if t == nil { + return t + } + for t.left != nil { + t = t.left + } + return t +} + +func (t *node32) max() *node32 { + if t == nil { + return t + } + for t.right != nil { + t = t.right + } + return t +} + +func (t *node32) glb(key int32, allow_eq bool) *node32 { + var best *node32 = nil + for t != nil { + if key <= t.key { + if allow_eq && key == t.key { + return t + } + // t is too big, glb is to left. + t = t.left + } else { + // t is a lower bound, record it and seek a better one. + best = t + t = t.right + } + } + return best +} + +func (t *node32) lub(key int32, allow_eq bool) *node32 { + var best *node32 = nil + for t != nil { + if key >= t.key { + if allow_eq && key == t.key { + return t + } + // t is too small, lub is to right. + t = t.right + } else { + // t is an upper bound, record it and seek a better one. + best = t + t = t.left + } + } + return best +} + +func (t *node32) aInsert(x int32) (newroot, newnode, oldnode *node32) { + // oldnode default of nil is good, others should be assigned. + if x == t.key { + oldnode = t + newt := *t + newnode = &newt + newroot = newnode + return + } + if x < t.key { + if t.left == nil { + t = t.copy() + n := makeNode(x) + t.left = n + newnode = n + newroot = t + t.height_ = 2 // was balanced w/ 0, sibling is height 0 or 1 + return + } + var new_l *node32 + new_l, newnode, oldnode = t.left.aInsert(x) + t = t.copy() + t.left = new_l + if new_l.height() > 1+t.right.height() { + newroot = t.aLeftIsHigh(newnode) + } else { + t.height_ = 1 + max(t.left.height(), t.right.height()) + newroot = t + } + } else { // x > t.key + if t.right == nil { + t = t.copy() + n := makeNode(x) + t.right = n + newnode = n + newroot = t + t.height_ = 2 // was balanced w/ 0, sibling is height 0 or 1 + return + } + var new_r *node32 + new_r, newnode, oldnode = t.right.aInsert(x) + t = t.copy() + t.right = new_r + if new_r.height() > 1+t.left.height() { + newroot = t.aRightIsHigh(newnode) + } else { + t.height_ = 1 + max(t.left.height(), t.right.height()) + newroot = t + } + } + return +} + +func (t *node32) aDelete(key int32) (deleted, newSubTree *node32) { + if t == nil { + return nil, nil + } + + if key < t.key { + oh := t.left.height() + d, tleft := t.left.aDelete(key) + if tleft == t.left { + return d, t + } + return d, t.copy().aRebalanceAfterLeftDeletion(oh, tleft) + } else if key > t.key { + oh := t.right.height() + d, tright := t.right.aDelete(key) + if tright == t.right { + return d, t + } + return d, t.copy().aRebalanceAfterRightDeletion(oh, tright) + } + + if t.height() == LEAF_HEIGHT { + return t, nil + } + + // Interior delete by removing left.Max or right.Min, + // then swapping contents + if t.left.height() > t.right.height() { + oh := t.left.height() + d, tleft := t.left.aDeleteMax() + r := t + t = t.copy() + t.data, t.key = d.data, d.key + return r, t.aRebalanceAfterLeftDeletion(oh, tleft) + } + + oh := t.right.height() + d, tright := t.right.aDeleteMin() + r := t + t = t.copy() + t.data, t.key = d.data, d.key + return r, t.aRebalanceAfterRightDeletion(oh, tright) +} + +func (t *node32) aDeleteMin() (deleted, newSubTree *node32) { + if t == nil { + return nil, nil + } + if t.left == nil { // leaf or left-most + return t, t.right + } + oh := t.left.height() + d, tleft := t.left.aDeleteMin() + if tleft == t.left { + return d, t + } + return d, t.copy().aRebalanceAfterLeftDeletion(oh, tleft) +} + +func (t *node32) aDeleteMax() (deleted, newSubTree *node32) { + if t == nil { + return nil, nil + } + + if t.right == nil { // leaf or right-most + return t, t.left + } + + oh := t.right.height() + d, tright := t.right.aDeleteMax() + if tright == t.right { + return d, t + } + return d, t.copy().aRebalanceAfterRightDeletion(oh, tright) +} + +func (t *node32) aRebalanceAfterLeftDeletion(oldLeftHeight int8, tleft *node32) *node32 { + t.left = tleft + + if oldLeftHeight == tleft.height() || oldLeftHeight == t.right.height() { + // this node is still balanced and its height is unchanged + return t + } + + if oldLeftHeight > t.right.height() { + // left was larger + t.height_-- + return t + } + + // left height fell by 1 and it was already less than right height + t.right = t.right.copy() + return t.aRightIsHigh(nil) +} + +func (t *node32) aRebalanceAfterRightDeletion(oldRightHeight int8, tright *node32) *node32 { + t.right = tright + + if oldRightHeight == tright.height() || oldRightHeight == t.left.height() { + // this node is still balanced and its height is unchanged + return t + } + + if oldRightHeight > t.left.height() { + // left was larger + t.height_-- + return t + } + + // right height fell by 1 and it was already less than left height + t.left = t.left.copy() + return t.aLeftIsHigh(nil) +} + +// aRightIsHigh does rotations necessary to fix a high right child +// assume that t and t.right are already fresh copies. +func (t *node32) aRightIsHigh(newnode *node32) *node32 { + right := t.right + if right.right.height() < right.left.height() { + // double rotation + if newnode != right.left { + right.left = right.left.copy() + } + t.right = right.leftToRoot() + } + t = t.rightToRoot() + return t +} + +// aLeftIsHigh does rotations necessary to fix a high left child +// assume that t and t.left are already fresh copies. +func (t *node32) aLeftIsHigh(newnode *node32) *node32 { + left := t.left + if left.left.height() < left.right.height() { + // double rotation + if newnode != left.right { + left.right = left.right.copy() + } + t.left = left.rightToRoot() + } + t = t.leftToRoot() + return t +} + +// rightToRoot does that rotation, modifying t and t.right in the process. +func (t *node32) rightToRoot() *node32 { + // this + // left right + // rl rr + // + // becomes + // + // right + // this rr + // left rl + // + right := t.right + rl := right.left + right.left = t + // parent's child ptr fixed in caller + t.right = rl + t.height_ = 1 + max(rl.height(), t.left.height()) + right.height_ = 1 + max(t.height(), right.right.height()) + return right +} + +// leftToRoot does that rotation, modifying t and t.left in the process. +func (t *node32) leftToRoot() *node32 { + // this + // left right + // ll lr + // + // becomes + // + // left + // ll this + // lr right + // + left := t.left + lr := left.right + left.right = t + // parent's child ptr fixed in caller + t.left = lr + t.height_ = 1 + max(lr.height(), t.right.height()) + left.height_ = 1 + max(t.height(), left.left.height()) + return left +} + +func max(a, b int8) int8 { + if a > b { + return a + } + return b +} + +func (t *node32) copy() *node32 { + u := *t + return &u +} |