summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/ssa/redblack32.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/ssa/redblack32.go')
-rw-r--r--src/cmd/compile/internal/ssa/redblack32.go429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/redblack32.go b/src/cmd/compile/internal/ssa/redblack32.go
new file mode 100644
index 0000000..fc9cc71
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/redblack32.go
@@ -0,0 +1,429 @@
+// Copyright 2016 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 ssa
+
+import "fmt"
+
+const (
+ rankLeaf rbrank = 1
+ rankZero rbrank = 0
+)
+
+type rbrank int8
+
+// RBTint32 is a red-black tree with data stored at internal nodes,
+// following Tarjan, Data Structures and Network Algorithms,
+// pp 48-52, using explicit rank instead of red and black.
+// Deletion is not yet implemented because it is not yet needed.
+// Extra operations glb, lub, glbEq, lubEq are provided for
+// use in sparse lookup algorithms.
+type RBTint32 struct {
+ root *node32
+ // An extra-clever implementation will have special cases
+ // for small sets, but we are not extra-clever today.
+}
+
+func (t *RBTint32) String() string {
+ if t.root == nil {
+ return "[]"
+ }
+ return "[" + t.root.String() + "]"
+}
+
+func (t *node32) String() string {
+ s := ""
+ if t.left != nil {
+ s = t.left.String() + " "
+ }
+ s = s + fmt.Sprintf("k=%d,d=%v", t.key, t.data)
+ if t.right != nil {
+ s = s + " " + t.right.String()
+ }
+ return s
+}
+
+type node32 struct {
+ // Standard conventions hold for left = smaller, right = larger
+ left, right, parent *node32
+ data interface{}
+ key int32
+ rank rbrank // From Tarjan pp 48-49:
+ // If x is a node with a parent, then x.rank <= x.parent.rank <= x.rank+1.
+ // If x is a node with a grandparent, then x.rank < x.parent.parent.rank.
+ // If x is an "external [null] node", then x.rank = 0 && x.parent.rank = 1.
+ // Any node with one or more null children should have rank = 1.
+}
+
+// makeNode returns a new leaf node with the given key and nil data.
+func (t *RBTint32) makeNode(key int32) *node32 {
+ return &node32{key: key, rank: rankLeaf}
+}
+
+// IsEmpty reports whether t is empty.
+func (t *RBTint32) IsEmpty() bool {
+ return t.root == nil
+}
+
+// IsSingle reports whether t is a singleton (leaf).
+func (t *RBTint32) 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 *RBTint32) VisitInOrder(f func(int32, interface{})) {
+ if t.root == nil {
+ return
+ }
+ t.root.visitInOrder(f)
+}
+
+func (n *node32) Data() interface{} {
+ if n == nil {
+ return nil
+ }
+ return n.data
+}
+
+func (n *node32) keyAndData() (k int32, d interface{}) {
+ if n == nil {
+ k = 0
+ d = nil
+ } else {
+ k = n.key
+ d = n.data
+ }
+ return
+}
+
+func (n *node32) Rank() rbrank {
+ if n == nil {
+ return 0
+ }
+ return n.rank
+}
+
+// Find returns the data associated with key in the tree, or
+// nil if key is not in the tree.
+func (t *RBTint32) Find(key int32) interface{} {
+ return t.root.find(key).Data()
+}
+
+// Insert adds key to the tree and associates key with data.
+// If key was already in the tree, it updates the associated data.
+// Insert returns the previous data associated with key,
+// or nil if key was not present.
+// Insert panics if data is nil.
+func (t *RBTint32) Insert(key int32, data interface{}) interface{} {
+ if data == nil {
+ panic("Cannot insert nil data into tree")
+ }
+ n := t.root
+ var newroot *node32
+ if n == nil {
+ n = t.makeNode(key)
+ newroot = n
+ } else {
+ newroot, n = n.insert(key, t)
+ }
+ r := n.data
+ n.data = data
+ t.root = newroot
+ return r
+}
+
+// Min returns the minimum element of t and its associated data.
+// If t is empty, then (0, nil) is returned.
+func (t *RBTint32) Min() (k int32, d interface{}) {
+ return t.root.min().keyAndData()
+}
+
+// Max returns the maximum element of t and its associated data.
+// If t is empty, then (0, nil) is returned.
+func (t *RBTint32) Max() (k int32, d interface{}) {
+ return t.root.max().keyAndData()
+}
+
+// Glb returns the greatest-lower-bound-exclusive of x and its associated
+// data. If x has no glb in the tree, then (0, nil) is returned.
+func (t *RBTint32) Glb(x int32) (k int32, d interface{}) {
+ return t.root.glb(x, false).keyAndData()
+}
+
+// GlbEq returns the greatest-lower-bound-inclusive of x and its associated
+// data. If x has no glbEQ in the tree, then (0, nil) is returned.
+func (t *RBTint32) GlbEq(x int32) (k int32, d interface{}) {
+ return t.root.glb(x, true).keyAndData()
+}
+
+// Lub returns the least-upper-bound-exclusive of x and its associated
+// data. If x has no lub in the tree, then (0, nil) is returned.
+func (t *RBTint32) Lub(x int32) (k int32, d interface{}) {
+ return t.root.lub(x, false).keyAndData()
+}
+
+// LubEq returns the least-upper-bound-inclusive of x and its associated
+// data. If x has no lubEq in the tree, then (0, nil) is returned.
+func (t *RBTint32) LubEq(x int32) (k int32, d interface{}) {
+ return t.root.lub(x, true).keyAndData()
+}
+
+func (t *node32) isLeaf() bool {
+ return t.left == nil && t.right == nil
+}
+
+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) maxChildRank() rbrank {
+ if t.left == nil {
+ if t.right == nil {
+ return rankZero
+ }
+ return t.right.rank
+ }
+ if t.right == nil {
+ return t.left.rank
+ }
+ if t.right.rank > t.left.rank {
+ return t.right.rank
+ }
+ return t.left.rank
+}
+
+func (t *node32) minChildRank() rbrank {
+ if t.left == nil || t.right == nil {
+ return rankZero
+ }
+ if t.right.rank < t.left.rank {
+ return t.right.rank
+ }
+ return t.left.rank
+}
+
+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
+ for t != nil {
+ if key <= t.key {
+ if key == t.key && allow_eq {
+ 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
+ for t != nil {
+ if key >= t.key {
+ if key == t.key && allow_eq {
+ return t
+ }
+ // t is too small, lub is to right.
+ t = t.right
+ } else {
+ // t is a upper bound, record it and seek a better one.
+ best = t
+ t = t.left
+ }
+ }
+ return best
+}
+
+func (t *node32) insert(x int32, w *RBTint32) (newroot, newnode *node32) {
+ // defaults
+ newroot = t
+ newnode = t
+ if x == t.key {
+ return
+ }
+ if x < t.key {
+ if t.left == nil {
+ n := w.makeNode(x)
+ n.parent = t
+ t.left = n
+ newnode = n
+ return
+ }
+ var new_l *node32
+ new_l, newnode = t.left.insert(x, w)
+ t.left = new_l
+ new_l.parent = t
+ newrank := 1 + new_l.maxChildRank()
+ if newrank > t.rank {
+ if newrank > 1+t.right.Rank() { // rotations required
+ if new_l.left.Rank() < new_l.right.Rank() {
+ // double rotation
+ t.left = new_l.rightToRoot()
+ }
+ newroot = t.leftToRoot()
+ return
+ } else {
+ t.rank = newrank
+ }
+ }
+ } else { // x > t.key
+ if t.right == nil {
+ n := w.makeNode(x)
+ n.parent = t
+ t.right = n
+ newnode = n
+ return
+ }
+ var new_r *node32
+ new_r, newnode = t.right.insert(x, w)
+ t.right = new_r
+ new_r.parent = t
+ newrank := 1 + new_r.maxChildRank()
+ if newrank > t.rank {
+ if newrank > 1+t.left.Rank() { // rotations required
+ if new_r.right.Rank() < new_r.left.Rank() {
+ // double rotation
+ t.right = new_r.leftToRoot()
+ }
+ newroot = t.rightToRoot()
+ return
+ } else {
+ t.rank = newrank
+ }
+ }
+ }
+ return
+}
+
+func (t *node32) rightToRoot() *node32 {
+ // this
+ // left right
+ // rl rr
+ //
+ // becomes
+ //
+ // right
+ // this rr
+ // left rl
+ //
+ right := t.right
+ rl := right.left
+ right.parent = t.parent
+ right.left = t
+ t.parent = right
+ // parent's child ptr fixed in caller
+ t.right = rl
+ if rl != nil {
+ rl.parent = t
+ }
+ return right
+}
+
+func (t *node32) leftToRoot() *node32 {
+ // this
+ // left right
+ // ll lr
+ //
+ // becomes
+ //
+ // left
+ // ll this
+ // lr right
+ //
+ left := t.left
+ lr := left.right
+ left.parent = t.parent
+ left.right = t
+ t.parent = left
+ // parent's child ptr fixed in caller
+ t.left = lr
+ if lr != nil {
+ lr.parent = t
+ }
+ return left
+}
+
+// next returns the successor of t in a left-to-right
+// walk of the tree in which t is embedded.
+func (t *node32) next() *node32 {
+ // If there is a right child, it is to the right
+ r := t.right
+ if r != nil {
+ return r.min()
+ }
+ // if t is p.left, then p, else repeat.
+ p := t.parent
+ for p != nil {
+ if p.left == t {
+ return p
+ }
+ t = p
+ p = t.parent
+ }
+ return nil
+}
+
+// prev returns the predecessor of t in a left-to-right
+// walk of the tree in which t is embedded.
+func (t *node32) prev() *node32 {
+ // If there is a left child, it is to the left
+ l := t.left
+ if l != nil {
+ return l.max()
+ }
+ // if t is p.right, then p, else repeat.
+ p := t.parent
+ for p != nil {
+ if p.right == t {
+ return p
+ }
+ t = p
+ p = t.parent
+ }
+ return nil
+}