summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/abt/avlint32.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:19:13 +0000
commitccd992355df7192993c666236047820244914598 (patch)
treef00fea65147227b7743083c6148396f74cd66935 /src/cmd/compile/internal/abt/avlint32.go
parentInitial commit. (diff)
downloadgolang-1.21-ccd992355df7192993c666236047820244914598.tar.xz
golang-1.21-ccd992355df7192993c666236047820244914598.zip
Adding upstream version 1.21.8.upstream/1.21.8
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.go832
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
+}