Simplify Clock/ClockMark design

- Do not require initialElapsed parameter
- Introduce instead ClockMark +- Duration operators
- Do not require ClockMark to expose its originating Clock back
- Turn elapsedFrom property into elapsed() function
- Rename abstract clock classes
- Fix unit of abstract clocks when constructing them

Add top-level docs for Clocks
This commit is contained in:
Ilya Gorbunov
2019-04-15 22:27:02 +03:00
parent ca29cfb88d
commit b5d16f1a9b
5 changed files with 78 additions and 55 deletions
+38 -16
View File
@@ -5,27 +5,49 @@
package kotlin.time
/**
* A source of time for measuring time intervals.
*
* The only operation provided by the clock is [mark]. It returns a [ClockMark], which can be used to query the elapsed time later.
*
* @see [measureTime]
* @see [withMeasureTime]
*/
public interface Clock {
/**
* Marks a time point on this clock.
*
* @param initialElapsed An initial value of [ClockMark.elapsedFrom] property of the resulting [ClockMark]:
*
* - pass [Duration.ZERO] to mark a time point that is now.
* - pass a positive duration to mark a time point in the past.
* - pass a negative duration to mark a time point in the future.
*
*/
fun mark(initialElapsed: Duration = Duration.ZERO): ClockMark
companion object {
val Default: Clock get() = MonoClock
}
fun mark(): ClockMark
}
/**
* Represents a time point notched on a particular [Clock]. Remains bound to the clock it was taken from
* and allows querying for the duration of time elapsed from that point (see the function [elapsed]).
*/
public interface ClockMark {
val clock: Clock
val elapsedFrom: Duration
/**
* Returns the amount of time passed from this clock mark on the clock from which this mark was taken.
*/
fun elapsed(): Duration
/**
* Returns a clock mark on the same clock that is ahead of this clock mark by the specified [duration].
*
* The returned clock mark is more _late_ when the [duration] is positive, and more _early_ when the [duration] is negative.
*/
operator fun plus(duration: Duration): ClockMark = AdjustedClockMark(this, duration)
/**
* Returns a clock mark on the same clock that is behind this clock mark by the specified [duration].
*
* The returned clock mark is more _early_ when the [duration] is positive, and more _late_ when the [duration] is negative.
*/
operator fun minus(duration: Duration): ClockMark = plus(-duration)
}
private class AdjustedClockMark(val mark: ClockMark, val adjustment: Duration) : ClockMark {
override fun elapsed(): Duration = mark.elapsed() - adjustment
override fun plus(duration: Duration): ClockMark = AdjustedClockMark(mark, adjustment + duration)
}
+28 -23
View File
@@ -7,49 +7,54 @@ package kotlin.time
import kotlin.js.JsName
/**
* The most precise clock available in the platform, whose readings increase monotonically over time.
*/
public expect object MonoClock : Clock
/**
* An abstract class used to implement clocks that return their readings as [Long] values in the specified [unit].
*/
public abstract class AbstractLongClock(protected val unit: DurationUnit) : Clock {
protected abstract fun read(): Long
public abstract class LongReadingClock : Clock {
abstract fun reading(): Long
abstract val unit: DurationUnit
override fun mark(initialElapsed: Duration): ClockMark = object : ClockMark {
val startedAt = reading()
override val clock: Clock get() = this@LongReadingClock
override val elapsedFrom: Duration get() = Duration(reading() - startedAt, this@LongReadingClock.unit) + initialElapsed
override fun mark(): ClockMark = object : ClockMark {
val startedAt = read()
override fun elapsed(): Duration = Duration(read() - startedAt, this@AbstractLongClock.unit)
}
}
public abstract class DoubleReadingClock : Clock {
abstract fun reading(): Double
abstract val unit: DurationUnit
/**
* An abstract class used to implement clocks that return their readings as [Double] values in the specified [unit].
*/
public abstract class AbstractDoubleClock(protected val unit: DurationUnit) : Clock {
protected abstract fun read(): Double
override fun mark(initialElapsed: Duration): ClockMark = object : ClockMark {
val startedAt = reading()
override val clock: Clock get() = this@DoubleReadingClock
override val elapsedFrom: Duration get() = Duration(reading() - startedAt, this@DoubleReadingClock.unit) + initialElapsed
override fun mark(): ClockMark = object : ClockMark {
val startedAt = read()
override fun elapsed(): Duration = Duration(read() - startedAt, this@AbstractDoubleClock.unit)
}
}
/**
* A clock, whose readings can be preset and changed manually. It is useful as a predictable source of time in tests.
*/
public class TestClock(
@JsName("readingValue")
var reading: Long = 0L,
override val unit: DurationUnit = DurationUnit.NANOSECONDS
) : LongReadingClock() {
override fun reading(): Long = reading
unit: DurationUnit = DurationUnit.NANOSECONDS
) : AbstractLongClock(unit) {
override fun read(): Long = reading
}
/*
public interface WallClock {
fun currentTimeMilliseconds(): Long
companion object : WallClock, LongReadingClock() {
companion object : WallClock, AbstractLongClock(unit = DurationUnit.MILLISECONDS) {
override fun currentTimeMilliseconds(): Long = System.currentTimeMillis()
override fun reading(): Long = System.currentTimeMillis()
override val unit: DurationUnit get() = DurationUnit.MILLISECONDS
override fun read(): Long = System.currentTimeMillis()
override fun toString(): String = "WallClock(System.currentTimeMillis())"
}
}
*/
@@ -22,7 +22,7 @@ public inline fun Clock.measureTime(action: () -> Unit): Duration {
val mark = mark()
action()
return mark.elapsedFrom
return mark.elapsed()
}
@@ -44,5 +44,5 @@ public inline fun <T> Clock.withMeasureTime(action: () -> T): DurationMeasured<T
val mark = mark()
val result = action()
return DurationMeasured(result, mark.elapsedFrom)
return DurationMeasured(result, mark.elapsed())
}