commonMain.HalfOpenRange.kt Maven / Gradle / Ivy
package io.fluidsonic.stdlib
// TODO add all special cases for Char, Double, Float, Long, UInt, ULong
public interface HalfOpenRange> {
public val start: Bound
public val endExclusive: Bound
public operator fun contains(value: Bound): Boolean =
value >= start && value < endExclusive
public fun isEmpty(): Boolean =
start >= endExclusive
public companion object
}
public fun > HalfOpenRange.contains(other: HalfOpenRange): Boolean =
contains(other.start) && other.endExclusive <= endExclusive
public fun > HalfOpenRange.flipped(): HalfOpenRange =
endExclusive rangeToExcluding start
public fun > HalfOpenRange.intersection(other: HalfOpenRange): HalfOpenRange? =
overlaps(other).thenTake { maxOf(start, other.start) rangeToExcluding minOf(endExclusive, other.endExclusive) }
public fun > HalfOpenRange.overlaps(other: HalfOpenRange): Boolean =
contains(other.start) || other.contains(start)
public inline fun > HalfOpenRange.mapBounds(transform: (Bound) -> Int): HalfOpenIntRange =
transform(start) rangeToExcluding transform(endExclusive)
public inline fun , R : Comparable> HalfOpenRange.mapBounds(transform: (Bound) -> R): HalfOpenRange =
transform(start) rangeToExcluding transform(endExclusive)
public fun > HalfOpenRange.subtracting(rangeToSubtract: HalfOpenRange): List> {
if (rangeToSubtract.start >= endExclusive || rangeToSubtract.endExclusive <= start)
return listOf(this)
val result = mutableListOf>()
if (rangeToSubtract.start > start)
result.add(start rangeToExcluding rangeToSubtract.start)
if (rangeToSubtract.endExclusive < endExclusive)
result.add(rangeToSubtract.endExclusive rangeToExcluding endExclusive)
return result
}
public fun > HalfOpenRange.toSequence(nextFunction: (Bound) -> Bound?): Sequence =
when {
isEmpty() -> emptySequence()
else -> generateSequence(start) { start ->
nextFunction(start)?.takeIf { value -> contains(value) }
}
}
private class HalfOpenComparableRange>(
override val start: Bound,
override val endExclusive: Bound
) : HalfOpenRange {
operator fun component1() =
start
operator fun component2() =
endExclusive
override fun equals(other: Any?) =
this === other || (other is HalfOpenRange<*> && start == other.start && endExclusive == other.endExclusive)
override fun hashCode() =
hash { start x endExclusive }
override fun toString() =
"$start ..< $endExclusive"
}
public infix fun > Bound.rangeToExcluding(that: Bound): HalfOpenRange =
HalfOpenComparableRange(this, that)