commonMain.jetbrains.datalore.base.composite.Composites.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lets-plot-common Show documentation
Show all versions of lets-plot-common Show documentation
Lets-Plot JVM package without rendering part
/*
* Copyright (c) 2019. JetBrains s.r.o.
* Use of this source code is governed by the MIT license that can be found in the LICENSE file.
*/
package jetbrains.datalore.base.composite
import jetbrains.datalore.base.function.Functions
import jetbrains.datalore.base.function.Predicate
import kotlin.math.min
object Composites {
private val ourWithBounds = CompositesWithBounds(0)
fun > removeFromParent(c: CompositeT) {
val parent = c.parent ?: return
parent.children().remove(c)
}
fun > isNonCompositeChild(c: CompositeT): Boolean {
if (c.parent == null) return false
if (c.nextSibling() != null) return false
if (c.prevSibling() != null) return false
val children = c.parent!!.children()
if (children.size != 1) return true
return children[0] !== c
}
fun > nextSibling(c: CompositeT): CompositeT? {
val parent = c.parent ?: return null
val index = parent.children().indexOf(c)
if (index == -1) return null
return if (index + 1 < parent.children().size) {
parent.children()[index + 1]
} else null
}
fun > prevSibling(c: CompositeT): CompositeT? {
val parent = c.parent ?: return null
val index = parent.children().indexOf(c)
if (index == -1) return null
return if (index > 0) {
parent.children()[index - 1]
} else null
}
fun > firstLeaf(c: CompositeT): CompositeT {
val first = c.firstChild() ?: return c
return firstLeaf(first)
}
fun > lastLeaf(c: CompositeT): CompositeT {
val last = c.lastChild() ?: return c
return lastLeaf(last)
}
fun > nextLeaf(c: CompositeT): CompositeT? {
return nextLeaf(c, null)
}
fun > nextLeaf(c: CompositeT, within: CompositeT?): CompositeT? {
var current = c
while (true) {
val nextSibling = current.nextSibling()
if (nextSibling != null) {
return firstLeaf(nextSibling)
}
if (isNonCompositeChild(current)) return null
val parent = current.parent
if (parent === within) return null
current = parent!!
}
}
fun > prevLeaf(c: CompositeT): CompositeT? {
return prevLeaf(c, null)
}
fun > prevLeaf(c: CompositeT, within: CompositeT?): CompositeT? {
var current = c
while (true) {
val prevSibling = current.prevSibling()
if (prevSibling != null) {
return lastLeaf(prevSibling)
}
if (isNonCompositeChild(current)) return null
val parent = current.parent
if (parent === within) return null
current = parent!!
}
}
fun > root(current: HasParentT): HasParentT {
var c = current
while (true) {
if (c.parent == null) {
return c
}
c = c.parent!!
}
}
/**
* @return Iterable containing the current node and all ancestors.
*/
fun > ancestorsFrom(current: HasParentT): Iterable {
return iterateFrom(current, {
it.parent
})
}
/**
* @return Iterable containing all ancestors, but not the current node.
*/
fun > ancestors(current: HasParentT): Iterable {
return iterate(current, {
it.parent
})
}
fun > nextLeaves(current: CompositeT): Iterable {
return iterate(current, {
nextLeaf(it)
})
}
fun > prevLeaves(current: CompositeT): Iterable {
return iterate(current, {
prevLeaf(it)
})
}
fun > nextNavOrder(current: CompositeT): Iterable {
return iterate(current, {
nextNavOrder(current, it)
})
}
fun > prevNavOrder(current: CompositeT): Iterable {
return iterate(current, {
prevNavOrder(current, it)
})
}
private fun > nextNavOrder(start: CompositeT, current: CompositeT): CompositeT? {
val nextSibling = current.nextSibling()
if (nextSibling != null) {
return firstLeaf(nextSibling)
}
if (isNonCompositeChild(current)) return null
val parent = current.parent
return if (!isDescendant(parent, start)) parent else nextNavOrder(start, parent!!)
}
private fun > prevNavOrder(start: CompositeT, current: CompositeT): CompositeT? {
val prevSibling = current.prevSibling()
if (prevSibling != null) {
return lastLeaf(prevSibling)
}
if (isNonCompositeChild(current)) return null
val parent = current.parent
return if (!isDescendant(parent, start)) parent else prevNavOrder(start, parent!!)
}
fun > isBefore(c1: CompositeT, c2: CompositeT): Boolean {
if (c1 === c2) return false
val c1a = reverseAncestors(c1)
val c2a = reverseAncestors(c2)
if (c1a[0] !== c2a[0]) {
throw IllegalArgumentException("Items are in different trees")
}
val commonLength = min(c1a.size, c2a.size)
for (i in 1 until commonLength) {
val first = c1a[i]
val second = c2a[i]
if (first !== second) {
return deltaBetween(first, second) > 0
}
}
throw IllegalArgumentException("One parameter is an ancestor of the other")
}
internal fun > deltaBetween(c1: CompositeT, c2: CompositeT): Int {
var left: CompositeT? = c1
var right: CompositeT? = c1
var delta = 0
while (true) {
if (left === c2) {
return -delta
}
if (right === c2) {
return delta
}
delta++
if (left == null && right == null) {
throw IllegalStateException("Both left and right are null")
}
if (left != null) {
left = left.prevSibling()
}
if (right != null) {
right = right.nextSibling()
}
}
}
/**
* @return Lowest common ancestor for the given nodes or `null` when they have no common ancestors.
*/
fun > commonAncestor(object1: HasParentT, object2: HasParentT): HasParentT? {
when {
object1 === object2 -> return object1
isDescendant(object1, object2) -> return object1
isDescendant(object2, object1) -> return object2
}
val stack1 = mutableListOf()
val stack2 = mutableListOf()
for (c in ancestorsFrom(object1)) {
stack1.add(c)
}
for (c in ancestorsFrom(object2)) {
stack2.add(c)
}
if (stack1.isEmpty() || stack2.isEmpty()) {
return null
} else {
do {
val pop1 = stack1.removeAt(stack1.size - 1)
val pop2 = stack2.removeAt(stack2.size - 1)
if (pop1 !== pop2) {
return pop1.parent
}
} while (stack1.isNotEmpty() && stack2.isNotEmpty())
return null
}
}
fun > getClosestAncestor(current: HasParentT,
acceptSelf: Boolean, p: Predicate): HasParentT? {
val ancestors = if (acceptSelf) ancestorsFrom(current) else ancestors(current)
for (c in ancestors) {
if (p.invoke(c)) {
return c
}
}
return null
}
fun > isDescendant(ancestor: Any?, current: HasParentT): Boolean {
return getClosestAncestor(current, true, Functions.same(ancestor)) != null
}
private fun > reverseAncestors(c: HasParentT): List {
val result = ArrayList()
collectReverseAncestors(c, result)
return result
}
private fun > collectReverseAncestors(c: HasParentT, result: MutableList) {
val parent = c.parent
if (parent != null) {
collectReverseAncestors(parent, result)
}
result.add(c)
}
internal fun toList(it: Iterable): List {
val result = ArrayList()
for (i in it) {
result.add(i)
}
return result
}
fun isLastChild(v: CompositeT): Boolean
where CompositeT : Composite, CompositeT : HasVisibility {
val parent = v.parent ?: return false
val siblings = parent.children()
val index = siblings.indexOf(v)
for (cv in siblings.subList(index + 1, siblings.size)) {
if (cv.visible().get()) return false
}
return true
}
fun isFirstChild(cell: CompositeT): Boolean
where CompositeT : Composite, CompositeT : HasVisibility {
val parent = cell.parent ?: return false
val siblings = parent.children()
val index = siblings.indexOf(cell)
for (cv in siblings.subList(0, index)) {
if (cv.visible().get()) return false
}
return true
}
fun firstFocusable(v: CompositeT): CompositeT?
where CompositeT : Composite, CompositeT : HasFocusability, CompositeT : HasVisibility {
return firstFocusable(v, true)
}
fun firstFocusable(v: CompositeT, deepest: Boolean): CompositeT?
where CompositeT : Composite, CompositeT : HasFocusability, CompositeT : HasVisibility {
for (cv in v.children()) {
if (!cv.visible().get()) continue
if (!deepest && cv.focusable().get()) return cv
val result = firstFocusable(cv)
if (null != result) return result
}
return if (v.focusable().get()) v else null
}
fun lastFocusable(c: CompositeT): CompositeT?
where CompositeT : Composite, CompositeT : HasFocusability, CompositeT : HasVisibility {
return lastFocusable(c, true)
}
fun lastFocusable(v: CompositeT, deepest: Boolean): CompositeT?
where CompositeT : Composite, CompositeT : HasFocusability, CompositeT : HasVisibility {
val children = v.children()
for (i in children.indices.reversed()) {
val cv = children[i]
if (!cv.visible().get()) continue
if (!deepest && cv.focusable().get()) return cv
val result = lastFocusable(cv, deepest)
if (null != result) return result
}
return if (v.focusable().get()) v else null
}
fun isVisible(v: HasParentT): Boolean
where HasParentT : HasParent, HasParentT : HasVisibility {
return null == getClosestAncestor(v, true) {
!it.visible().get()
}
}
fun focusableParent(v: HasParentT): HasParentT?
where HasParentT : HasParent, HasParentT : HasFocusability {
return focusableParent(v, false)
}
fun focusableParent(v: HasParentT, acceptSelf: Boolean): HasParentT?
where HasParentT : HasParent, HasParentT : HasFocusability {
return getClosestAncestor(v, acceptSelf) {
it.focusable().get()
}
}
fun isFocusable(v: HasParentT): Boolean
where HasParentT : HasParent, HasParentT : HasFocusability, HasParentT : HasVisibility {
return v.focusable().get() && isVisible(v)
}
fun > next(c: CompositeT, p: Predicate): CompositeT? {
for (next in nextNavOrder(c)) {
if (p.invoke(next)) return next
}
return null
}
fun > prev(v: CompositeT, p: Predicate): CompositeT? {
for (prev in prevNavOrder(v)) {
if (p.invoke(prev)) return prev
}
return null
}
fun nextFocusable(v: CompositeT): CompositeT?
where CompositeT : NavComposite, CompositeT : HasFocusability, CompositeT : HasVisibility {
for (cv in nextNavOrder(v)) {
if (isFocusable(cv)) return cv
}
return null
}
fun prevFocusable(v: CompositeT): CompositeT?
where CompositeT : NavComposite, CompositeT : HasFocusability, CompositeT : HasVisibility {
for (cv in prevNavOrder(v)) {
if (isFocusable(cv)) return cv
}
return null
}
internal fun iterate(initial: ValueT, trans: (ValueT) -> ValueT?): Iterable {
return iterateFrom(trans(initial), trans)
}
private fun iterateFrom(initial: ValueT?, trans: (ValueT) -> ValueT?): Iterable {
return object : Iterable {
override fun iterator(): Iterator {
return object : Iterator {
private var myCurrent: ValueT? = initial
override fun hasNext(): Boolean {
return myCurrent != null
}
override fun next(): ValueT {
if (myCurrent == null) {
throw NoSuchElementException()
}
val result = myCurrent
myCurrent = trans(result!!)
return result
}
}
}
}
}
/**
* Returns a list that includes all nodes that have some parent strictly between
* some parents of `from` and `from`.
*/
fun > allBetween(from: CompositeT, to: CompositeT): List {
val res = ArrayList()
if (to !== from) {
includeClosed(from, to, res)
}
return res
}
private fun > includeClosed(left: CompositeT, to: CompositeT, res: MutableList) {
var next = left.nextSibling()
while (next != null) {
if (includeOpen(next, to, res)) {
return
}
next = next.nextSibling()
}
if (left.parent == null) {
throw IllegalArgumentException("Right bound not found in left's bound hierarchy. to=$to")
}
includeClosed(left.parent!!, to, res)
}
private fun > includeOpen(node: CompositeT, to: CompositeT, res: MutableList): Boolean {
if (node === to) {
return true
}
for (c in node.children()) {
if (includeOpen(c, to, res)) {
return true
}
}
res.add(node)
return false
}
//has bounds
fun isAbove(upper: CompositeT, lower: CompositeT): Boolean {
return ourWithBounds.isAbove(upper, lower)
}
fun isBelow(lower: CompositeT, upper: CompositeT): Boolean {
return ourWithBounds.isBelow(lower, upper)
}
fun homeElement(cell: CompositeT): CompositeT
where CompositeT : NavComposite, CompositeT : HasFocusability, CompositeT : HasVisibility, CompositeT : HasBounds {
return ourWithBounds.homeElement(cell)
}
fun endElement(cell: CompositeT): CompositeT
where CompositeT : NavComposite, CompositeT : HasFocusability, CompositeT : HasVisibility, CompositeT : HasBounds {
return ourWithBounds.endElement(cell)
}
fun upperFocusable(v: CompositeT, xOffset: Int): CompositeT?
where CompositeT : NavComposite, CompositeT : HasFocusability, CompositeT : HasVisibility, CompositeT : HasBounds {
return ourWithBounds.upperFocusable(v, xOffset)
}
fun lowerFocusable(v: CompositeT, xOffset: Int): CompositeT?
where CompositeT : NavComposite, CompositeT : HasFocusability, CompositeT : HasVisibility, CompositeT : HasBounds {
return ourWithBounds.lowerFocusable(v, xOffset)
}
// See also test: CompositesTest#iterateBranch
// fun > preOrderTraversal(root: CompositeT): Iterable {
// return Composites.createCompositeTreeTraverser().preOrderTraversal(root)
// }
//
// private fun > createCompositeTreeTraverser(): TreeTraverser {
// return TreeTraverser.using(object : com.google.common.base.Function>() {
// fun apply(input: CompositeT?): Iterable {
// return if (input == null) emptyList() else input.children()
// }
// })
// }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy