commonMain.io.islandtime.ranges.TimePointProgressions.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-metadata Show documentation
Show all versions of core-metadata Show documentation
A multiplatform library for working with dates and times
package io.islandtime.ranges
import io.islandtime.base.TimePoint
import io.islandtime.measures.*
/**
* A time point progression builder.
*
* Without a step, a time-based progression can't be created. This interface represents an intermediate state in the
* process of creating a time point progression.
*/
interface TimePointProgressionBuilder> {
val first: T
val last: T
}
/**
* Progression builder that stores just the first and last elements.
*/
private class DefaultTimePointProgressionBuilder>(
override val first: T,
override val last: T
) : TimePointProgressionBuilder
class TimePointSecondProgression> private constructor(
override val first: T,
endInclusive: T,
val step: LongSeconds
) : TimePointProgressionBuilder,
Iterable {
init {
require(!step.isZero()) { "Step must be non-zero" }
}
override val last: T = getLastTimePointInProgression(first, endInclusive, step)
fun isEmpty(): Boolean = if (step.isPositive()) first > last else first < last
override fun iterator(): TimePointIterator = TimePointSecondProgressionIterator(first, last, step)
override fun toString(): String {
return if (step.isPositive()) {
"$first..$last step $step"
} else {
"$first downTo $last step ${-step}"
}
}
override fun equals(other: Any?): Boolean {
return other is TimePointSecondProgression<*> &&
(isEmpty() && other.isEmpty() ||
first == other.first &&
last == other.last &&
step == other.step)
}
override fun hashCode(): Int {
return if (isEmpty()) {
-1
} else {
31 * (31 * first.hashCode() + last.hashCode()) + step.hashCode()
}
}
/**
* Reverse a progression such that it counts down instead of up, or vice versa
*/
fun reversed(): TimePointSecondProgression {
return fromClosedRange(last, first, -step)
}
companion object {
fun > fromClosedRange(
rangeStart: T,
rangeEnd: T,
step: LongSeconds
) = TimePointSecondProgression(rangeStart, rangeEnd, step)
}
}
class TimePointNanosecondProgression> private constructor(
override val first: T,
endInclusive: T,
val step: LongNanoseconds
) : TimePointProgressionBuilder,
Iterable {
init {
require(!step.isZero()) { "Step must be non-zero" }
}
override val last: T = getLastTimePointInProgression(first, endInclusive, step)
fun isEmpty(): Boolean = if (step.isPositive()) first > last else first < last
override fun iterator(): TimePointIterator = TimePointNanosecondProgressionIterator(first, last, step)
override fun toString(): String {
return if (step.isPositive()) {
"$first..$last step $step"
} else {
"$first downTo $last step ${-step}"
}
}
override fun equals(other: Any?): Boolean {
return other is TimePointNanosecondProgression<*> &&
(isEmpty() && other.isEmpty() ||
first == other.first &&
last == other.last &&
step == other.step)
}
override fun hashCode(): Int {
return if (isEmpty()) {
-1
} else {
31 * (31 * first.hashCode() + last.hashCode()) + step.hashCode()
}
}
/**
* Reverse a progression such that it counts down instead of up, or vice versa
*/
fun reversed(): TimePointNanosecondProgression {
return fromClosedRange(last, first, -step)
}
companion object {
fun > fromClosedRange(
rangeStart: T,
rangeEnd: T,
step: LongNanoseconds
) = TimePointNanosecondProgression(rangeStart, rangeEnd, step)
}
}
/**
* Get a progression of time points in descending order.
*/
infix fun > T.downTo(to: T): TimePointProgressionBuilder {
return DefaultTimePointProgressionBuilder(this, to)
}
infix fun > TimePointProgressionBuilder.step(step: IntDays): TimePointSecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongDays()
val secondStep = (if (last > first) longStep else longStep.negateUnchecked()).inSecondsUnchecked
return TimePointSecondProgression.fromClosedRange(first, last, secondStep)
}
infix fun > TimePointProgressionBuilder.step(step: IntHours): TimePointSecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongHours()
val secondStep = (if (last > first) longStep else longStep.negateUnchecked()).inSecondsUnchecked
return TimePointSecondProgression.fromClosedRange(first, last, secondStep)
}
infix fun > TimePointProgressionBuilder.step(step: IntMinutes): TimePointSecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongMinutes()
val secondStep = (if (last > first) longStep else longStep.negateUnchecked()).inSecondsUnchecked
return TimePointSecondProgression.fromClosedRange(first, last, secondStep)
}
infix fun > TimePointProgressionBuilder.step(step: IntSeconds): TimePointSecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongSeconds()
val secondStep = (if (last > first) longStep else longStep.negateUnchecked())
return TimePointSecondProgression.fromClosedRange(first, last, secondStep)
}
infix fun > TimePointProgressionBuilder.step(
step: IntMilliseconds
): TimePointNanosecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongMilliseconds()
val nanoStep = (if (last > first) longStep else longStep.negateUnchecked()).inNanosecondsUnchecked
return TimePointNanosecondProgression.fromClosedRange(first, last, nanoStep)
}
infix fun > TimePointProgressionBuilder.step(
step: LongMilliseconds
): TimePointNanosecondProgression {
require(step.value > 0) { "step must be positive" }
val nanoStep = (if (last > first) step else -step).inNanoseconds
return TimePointNanosecondProgression.fromClosedRange(first, last, nanoStep)
}
infix fun > TimePointProgressionBuilder.step(
step: IntMicroseconds
): TimePointNanosecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongMicroseconds()
val nanoStep = (if (last > first) longStep else longStep.negateUnchecked()).inNanosecondsUnchecked
return TimePointNanosecondProgression.fromClosedRange(first, last, nanoStep)
}
infix fun > TimePointProgressionBuilder.step(
step: LongMicroseconds
): TimePointNanosecondProgression {
require(step.value > 0) { "step must be positive" }
val nanoStep = (if (last > first) step else -step).inNanoseconds
return TimePointNanosecondProgression.fromClosedRange(first, last, nanoStep)
}
infix fun > TimePointProgressionBuilder.step(
step: IntNanoseconds
): TimePointNanosecondProgression {
require(step.value > 0) { "step must be positive" }
val longStep = step.toLongNanoseconds()
val nanoStep = if (last > first) longStep else longStep.negateUnchecked()
return TimePointNanosecondProgression.fromClosedRange(first, last, nanoStep)
}
infix fun > TimePointProgressionBuilder.step(
step: LongNanoseconds
): TimePointNanosecondProgression {
require(step.value > 0) { "step must be positive" }
val nanoStep = if (last > first) step else -step
return TimePointNanosecondProgression.fromClosedRange(first, last, nanoStep)
}
/**
* Assumes step is non-zero
*/
private fun > getLastTimePointInProgression(start: T, end: T, step: LongSeconds): T {
return if ((step.isPositive() && start >= end) || (step.isNegative() && start <= end)) {
end
} else {
val secondsBetween = secondsBetween(start, end)
val steppedSeconds = secondsBetween - (secondsBetween % step.value)
start + steppedSeconds
}
}
/**
* Assumes step is non-zero
*/
private fun > getLastTimePointInProgression(start: T, end: T, step: LongNanoseconds): T {
return if ((step.isPositive() && start >= end) || (step.isNegative() && start <= end)) {
end
} else {
val nanosecondsBetween = nanosecondsBetween(start, end)
val steppedNanoseconds = nanosecondsBetween - (nanosecondsBetween % step.value)
start + steppedNanoseconds
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy