You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
6.9 KiB
Kotlin
241 lines
6.9 KiB
Kotlin
package net.cijber.pubgrub.version
|
|
|
|
import net.cijber.pubgrub.SetRelation
|
|
import net.cijber.pubgrub.stubs.Version
|
|
|
|
open class VersionRange<V : Version<V>>(
|
|
val bottom: VersionBorder<V>?,
|
|
val top: VersionBorder<V>?
|
|
) :
|
|
VersionConstraint<V> {
|
|
|
|
override val isEmpty: Boolean = false
|
|
override val isAny: Boolean = bottom == null && top == null
|
|
|
|
infix fun relation(rhs: VersionRange<V>): SetRelation {
|
|
val topDiff = when {
|
|
top != null && rhs.top != null -> top.compareTo(rhs.top)
|
|
top != null -> -1
|
|
rhs.top != null -> 1
|
|
else -> 0
|
|
}
|
|
|
|
val bottomDiff = when {
|
|
bottom != null && rhs.bottom != null -> bottom.compareTo(rhs.bottom)
|
|
bottom != null -> 1
|
|
rhs.bottom != null -> -1
|
|
else -> 0
|
|
}
|
|
|
|
if (topDiff == 0 && bottomDiff == 0) {
|
|
return SetRelation.Equal
|
|
}
|
|
|
|
if (topDiff == 1 && bottomDiff == -1) {
|
|
return SetRelation.Superset
|
|
}
|
|
|
|
if (topDiff <= 0 && bottomDiff >= 0) {
|
|
return SetRelation.Subset
|
|
}
|
|
|
|
val topBottomDiff = when {
|
|
top != null && rhs.bottom != null -> top.compareTo(rhs.bottom)
|
|
else -> 1
|
|
}
|
|
|
|
val bottomTopDiff = when {
|
|
bottom != null && rhs.top != null -> bottom.compareTo(rhs.top)
|
|
else -> -1
|
|
}
|
|
if (bottomTopDiff == 1 || topBottomDiff == -1) {
|
|
return SetRelation.Disjoint
|
|
}
|
|
|
|
return SetRelation.Overlaps
|
|
}
|
|
|
|
override fun allowsAll(rhs: VersionConstraint<V>): Boolean {
|
|
if (rhs.isEmpty)
|
|
return true
|
|
|
|
if (rhs.isAny)
|
|
return false
|
|
|
|
if (rhs is VersionRange) {
|
|
return relation(rhs) in setOf(SetRelation.Equal, SetRelation.Superset)
|
|
}
|
|
|
|
if (rhs is VersionUnion) {
|
|
return rhs.constraints.all(this::allowsAll)
|
|
}
|
|
|
|
error("Unknown VersionConstraint: $rhs")
|
|
}
|
|
|
|
override fun allowsAny(rhs: VersionConstraint<V>): Boolean {
|
|
if (rhs.isEmpty || rhs.isAny)
|
|
return true
|
|
|
|
if (rhs is VersionRange) {
|
|
return relation(rhs) != SetRelation.Disjoint
|
|
}
|
|
|
|
if (rhs is VersionUnion) {
|
|
return rhs.constraints.any(this::allowsAny)
|
|
}
|
|
|
|
error("Unknown VersionConstraint: $rhs")
|
|
}
|
|
|
|
override fun allows(version: V): Boolean {
|
|
return (bottom?.beneath(version, true) ?: true) &&
|
|
(top?.above(version, true) ?: true)
|
|
}
|
|
|
|
override fun intersect(rhs: VersionConstraint<V>): VersionConstraint<V> {
|
|
if (rhs.isEmpty) {
|
|
return rhs
|
|
}
|
|
|
|
if (rhs.isAny) {
|
|
return this
|
|
}
|
|
|
|
if (rhs is VersionUnion) {
|
|
return rhs.intersect(this)
|
|
}
|
|
|
|
if (rhs is VersionRange) {
|
|
if (relation(rhs) != SetRelation.Disjoint) {
|
|
return VersionRange(
|
|
when {
|
|
rhs.bottom != null && bottom != null -> maxOf(rhs.bottom, bottom)
|
|
else -> bottom ?: rhs.bottom
|
|
},
|
|
when {
|
|
rhs.top != null && top != null -> minOf(rhs.top, top)
|
|
else -> top ?: rhs.top
|
|
}
|
|
)
|
|
}
|
|
|
|
return VersionEmpty()
|
|
}
|
|
|
|
error("Unkown VersionConstraint: $rhs")
|
|
}
|
|
|
|
override fun union(rhs: VersionConstraint<V>): VersionConstraint<V> {
|
|
if (rhs is VersionRange) {
|
|
return when (relation(rhs)) {
|
|
SetRelation.Superset, SetRelation.Equal -> this
|
|
SetRelation.Subset -> rhs
|
|
SetRelation.Overlaps -> VersionRange(
|
|
when {
|
|
rhs.bottom != null && bottom != null -> minOf(rhs.bottom, bottom)
|
|
else -> null
|
|
},
|
|
when {
|
|
rhs.top != null && top != null -> maxOf(rhs.top, top)
|
|
else -> null
|
|
}
|
|
)
|
|
SetRelation.Disjoint -> VersionUnion(listOf(this, rhs))
|
|
}
|
|
}
|
|
|
|
if (rhs is VersionEmpty) {
|
|
return this
|
|
}
|
|
|
|
if (rhs is VersionUnion) {
|
|
return VersionUnion(rhs.constraints + listOf(this))
|
|
}
|
|
|
|
error("Unknown VersionConstraint given: $rhs")
|
|
}
|
|
|
|
override fun difference(rhs: VersionConstraint<V>): VersionConstraint<V> {
|
|
if (rhs.isEmpty) {
|
|
return this
|
|
}
|
|
|
|
if (rhs.isAny) {
|
|
return VersionEmpty()
|
|
}
|
|
|
|
if (rhs is VersionUnion) {
|
|
val ranges = mutableListOf(this)
|
|
|
|
for (constraint in rhs.constraints) {
|
|
val rel = constraint relation ranges.last()
|
|
if (rel == SetRelation.Disjoint) {
|
|
continue
|
|
}
|
|
|
|
val last = ranges.dropLast(1).first()
|
|
|
|
val res = last.difference(constraint)
|
|
|
|
if (res.isEmpty) {
|
|
break
|
|
}
|
|
|
|
if (res is VersionUnion) {
|
|
ranges.addAll(res.constraints)
|
|
}
|
|
|
|
if (res is VersionRange) {
|
|
ranges.add(res)
|
|
}
|
|
}
|
|
|
|
return when (ranges.count()) {
|
|
0 -> VersionEmpty()
|
|
1 -> ranges.first()
|
|
else -> VersionUnion(ranges)
|
|
}
|
|
}
|
|
|
|
if (rhs is VersionRange) {
|
|
return when (rhs relation this) {
|
|
SetRelation.Disjoint -> this
|
|
SetRelation.Equal, SetRelation.Superset -> VersionEmpty()
|
|
SetRelation.Overlaps -> VersionRange(
|
|
when {
|
|
bottom != null && rhs.bottom != null && rhs.bottom < bottom -> rhs.top
|
|
else -> bottom
|
|
},
|
|
when {
|
|
top != null && rhs.top != null && rhs.top > top -> rhs.bottom
|
|
else -> top
|
|
}
|
|
)
|
|
SetRelation.Subset -> {
|
|
if (top == rhs.top) {
|
|
return VersionRange(bottom, rhs.bottom?.reversed())
|
|
}
|
|
|
|
if (bottom == rhs.bottom) {
|
|
return VersionRange(rhs.top?.reversed(), top)
|
|
}
|
|
|
|
return VersionUnion(
|
|
listOf(
|
|
VersionRange(bottom, rhs.bottom?.reversed()),
|
|
VersionRange(rhs.top?.reversed(), top)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
error("Unknown VersionConstraint given: $rhs")
|
|
}
|
|
|
|
companion object {
|
|
fun <V : Version<V>> single(version: V) =
|
|
VersionRange(VersionBorder.bottom(version), VersionBorder.top(version))
|
|
}
|
|
} |