blob: 1ec29760728daea2dba0706316d57ae421354f0e [file] [log] [blame]
// 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"
"testing"
)
type sstring string
func (s sstring) String() string {
return string(s)
}
// wellFormed ensures that a red-black tree meets
// all of its invariants and returns a string identifying
// the first problem encountered. If there is no problem
// then the returned string is empty. The size is also
// returned to allow comparison of calculated tree size
// with expected.
func (t *RBTint32) wellFormed() (s string, i int) {
if t.root == nil {
s = ""
i = 0
return
}
return t.root.wellFormedSubtree(nil, -0x80000000, 0x7fffffff)
}
// wellFormedSubtree ensures that a red-black subtree meets
// all of its invariants and returns a string identifying
// the first problem encountered. If there is no problem
// then the returned string is empty. The size is also
// returned to allow comparison of calculated tree size
// with expected.
func (t *node32) wellFormedSubtree(parent *node32, min, max int32) (s string, i int) {
i = -1 // initialize to a failing value
s = "" // s is the reason for failure; empty means okay.
if t.parent != parent {
s = "t.parent != parent"
return
}
if min >= t.key {
s = "min >= t.key"
return
}
if max <= t.key {
s = "max <= t.key"
return
}
l := t.left
r := t.right
if l == nil && r == nil {
if t.rank != rankLeaf {
s = "leaf rank wrong"
return
}
}
if l != nil {
if t.rank < l.rank {
s = "t.rank < l.rank"
} else if t.rank > 1+l.rank {
s = "t.rank > 1+l.rank"
} else if t.rank <= l.maxChildRank() {
s = "t.rank <= l.maxChildRank()"
} else if t.key <= l.key {
s = "t.key <= l.key"
}
if s != "" {
return
}
} else {
if t.rank != 1 {
s = "t w/ left nil has rank != 1"
return
}
}
if r != nil {
if t.rank < r.rank {
s = "t.rank < r.rank"
} else if t.rank > 1+r.rank {
s = "t.rank > 1+r.rank"
} else if t.rank <= r.maxChildRank() {
s = "t.rank <= r.maxChildRank()"
} else if t.key >= r.key {
s = "t.key >= r.key"
}
if s != "" {
return
}
} else {
if t.rank != 1 {
s = "t w/ right nil has rank != 1"
return
}
}
ii := 1
if l != nil {
res, il := l.wellFormedSubtree(t, min, t.key)
if res != "" {
s = "L." + res
return
}
ii += il
}
if r != nil {
res, ir := r.wellFormedSubtree(t, t.key, max)
if res != "" {
s = "R." + res
return
}
ii += ir
}
i = ii
return
}
func (t *RBTint32) DebugString() string {
if t.root == nil {
return ""
}
return t.root.DebugString()
}
// DebugString prints the tree with nested information
// to allow an eyeball check on the tree balance.
func (t *node32) DebugString() string {
s := ""
if t.left != nil {
s = s + "["
s = s + t.left.DebugString()
s = s + "]"
}
s = s + fmt.Sprintf("%v=%v:%d", t.key, t.data, t.rank)
if t.right != nil {
s = s + "["
s = s + t.right.DebugString()
s = s + "]"
}
return s
}
func allRBT32Ops(te *testing.T, x []int32) {
t := &RBTint32{}
for i, d := range x {
x[i] = d + d // Double everything for glb/lub testing
}
// fmt.Printf("Inserting double of %v", x)
k := 0
min := int32(0x7fffffff)
max := int32(-0x80000000)
for _, d := range x {
if d < min {
min = d
}
if d > max {
max = d
}
t.Insert(d, sstring(fmt.Sprintf("%v", d)))
k++
s, i := t.wellFormed()
if i != k {
te.Errorf("Wrong tree size %v, expected %v for %v", i, k, t.DebugString())
}
if s != "" {
te.Errorf("Tree consistency problem at %v", s)
return
}
}
oops := false
for _, d := range x {
s := fmt.Sprintf("%v", d)
f := t.Find(d)
// data
if s != fmt.Sprintf("%v", f) {
te.Errorf("s(%v) != f(%v)", s, f)
oops = true
}
}
if !oops {
for _, d := range x {
s := fmt.Sprintf("%v", d)
kg, g := t.Glb(d + 1)
kge, ge := t.GlbEq(d)
kl, l := t.Lub(d - 1)
kle, le := t.LubEq(d)
// keys
if d != kg {
te.Errorf("d(%v) != kg(%v)", d, kg)
}
if d != kl {
te.Errorf("d(%v) != kl(%v)", d, kl)
}
if d != kge {
te.Errorf("d(%v) != kge(%v)", d, kge)
}
if d != kle {
te.Errorf("d(%v) != kle(%v)", d, kle)
}
// data
if s != fmt.Sprintf("%v", g) {
te.Errorf("s(%v) != g(%v)", s, g)
}
if s != fmt.Sprintf("%v", l) {
te.Errorf("s(%v) != l(%v)", s, l)
}
if s != fmt.Sprintf("%v", ge) {
te.Errorf("s(%v) != ge(%v)", s, ge)
}
if s != fmt.Sprintf("%v", le) {
te.Errorf("s(%v) != le(%v)", s, le)
}
}
for _, d := range x {
s := fmt.Sprintf("%v", d)
kge, ge := t.GlbEq(d + 1)
kle, le := t.LubEq(d - 1)
if d != kge {
te.Errorf("d(%v) != kge(%v)", d, kge)
}
if d != kle {
te.Errorf("d(%v) != kle(%v)", d, kle)
}
if s != fmt.Sprintf("%v", ge) {
te.Errorf("s(%v) != ge(%v)", s, ge)
}
if s != fmt.Sprintf("%v", le) {
te.Errorf("s(%v) != le(%v)", s, le)
}
}
kg, g := t.Glb(min)
kge, ge := t.GlbEq(min - 1)
kl, l := t.Lub(max)
kle, le := t.LubEq(max + 1)
fmin := t.Find(min - 1)
fmax := t.Find(min + 11)
if kg != 0 || kge != 0 || kl != 0 || kle != 0 {
te.Errorf("Got non-zero-key for missing query")
}
if g != nil || ge != nil || l != nil || le != nil || fmin != nil || fmax != nil {
te.Errorf("Got non-error-data for missing query")
}
}
}
func TestAllRBTreeOps(t *testing.T) {
allRBT32Ops(t, []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25})
allRBT32Ops(t, []int32{22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 3, 2, 1, 25, 24, 23, 12, 11, 10, 9, 8, 7, 6, 5, 4})
allRBT32Ops(t, []int32{25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})
allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24})
allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2})
allRBT32Ops(t, []int32{24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25})
}