Files
kotlin-fork/compiler/testData/psi/examples/BinaryTree.kt
T
2013-09-17 18:10:00 +04:00

195 lines
4.9 KiB
Kotlin

class BinaryTree<T> : IMutableSet<T> {
private class TreeNode(
var value : T, var parent : TreeNode
) {
var left : TreeNode
var right : TreeNode
}
private val compare : MatchableComparison<T>
private var root : TreeNode
private var version = 0
// override var size : Int { get; private set; }
this(compare : Comparison<T>) {
this.compare = asMatchableComparison(comparison)
}
this() : this(naturalOrder<T>()) {
}
private [operator] fun T.compareTo(other : T) : Int = compare(this, other)
override fun contains(item : T) : Boolean {
return contains(root, item)
fun contains(node : TreeNode, item : T) : Boolean {
if (node == null) return false
when(compare(item, node.value)) {
EQ -> true
LS -> contains(node.left, item)
GT -> contains(node.right, item)
}
}
}
override fun add(item : T) : Boolean {
if (add(Ref(root), null)) {
size++
version++
return true
}
return false
// In principle, this has access to item anyway, but then it's unreachable code
// BAD: the naive implementation of ref will create H(T) ref objects, but can be optimized to create only one
fun add(node : Ref<TreeNode?>, parent : TreeNode) : Boolean {
if (node.value == null) {
node.value = TreeNode(item, parent)
return true
}
when (compare(item, node.value.value)) {
EQ -> false
LS -> add(ref node.value.left, node)
GT -> add(ref node.value.right, node)
}
}
// In principle, this has access to item anyway
fun addNoRef(node : TreeNode) : Boolean {
if (node == null) {
root = TreeNode(item, null)
return true
}
when (compare(item, node.value)) {
EQ -> return false
LS ->
if (node.left == null) {
node.left = TreeNode(item, node)
return true
} else return add(node.left)
GT ->
if (node.right == null) {
node.right = TreeNode(item, node)
return true
} else return add(node.right)
}
}
}
override fun remove(item : T) : Boolean {
val toRemove = find(root, item)
if (toRemove == null) return false
remove(toRemove)
size--
version++
return true
fun find(node : TreeNode) : TreeNode {
if (node == null) return null
when (compare(item, node.value)) {
EQ -> node
LS -> find(node.left)
GT -> find(node.right)
}
}
}
private fun remove(node : TreeNode) {
when (node) {
//is TreeNode #(null, null) -> replace(node, null)
//is TreeNode #(null, right) -> replace(node, right)
//is TreeNode #(left, null) -> replace(node, left)
//is TreeNode #(left, right) -> {
// val min = min(node.right)
// node.value = min.value
// remove(min)
//}
}
fun replace(node : TreeNode, replace : TreeNode) {
if (node == root) {
root = replace
return
}
if (node.parent.left == node) {
node.parent.left = replace
} else if (node.parent.right == node) {
node.parent.right = replace
} else Assert(false)
}
}
// Relies on tail-recursion optimization
private fun min(node : TreeNode) {
if (node.left == null) node else min(node.left)
}
override fun iterator() : IIterator<T> = mutableIterator()
override fun mutableIterator() : IMutableIterator<T> = object : IMutableIterator {
val version = BinaryTree.this.version
val down = Stack<TreeNode>()
val up = Stack<TreeNode>()
var lastNode : TreeNode
this() {
if (root != null)
down.push(root)
}
override fun next() : T {
if (!hasNext)
throw NoMoreElementsException()
checkVersion()
lastNode = nextNode()
return lastNode.value
}
private fun nextNode() : TreeNode {
while (true) {
if (!down.isEmpty) {
val curNode = down.pop()
if (curNode.left != null) {
up.push(curNode)
down.push(curNode.left)
} else {
if (curNode.right != null) {
down.push(curNode.right)
}
return curNode;
}
} else {
val curNode = up.pop()
if (curNode.right != null) {
down.push(curNode.right)
}
return curNode
}
}
}
override val hasNext : Boolean
get() = !down.isEmpty || !up.isEmpty
override fun remove() {
checkVersion()
if (lastNode == null)
throw IterationException("Nothing to remove")
remove(lastNode)
version++
BinaryTree.this.version = version
}
private fun checkVersion() {
if (version != BinaryTree.this.version) {
throw ConcurrentModificationException()
}
}
}
}