Make TimeMark returned by TimeSource.Monotonic a value class
This value class wraps Long on JVM and Native thus reducing allocations in time measurement scenarios when the default monotonic time source is statically known. KT-46132
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
|
||||
package kotlin.time
|
||||
|
||||
import kotlin.jvm.JvmInline
|
||||
|
||||
/**
|
||||
* A source of time for measuring time intervals.
|
||||
*
|
||||
@@ -30,7 +32,8 @@ public interface TimeSource {
|
||||
* This time source returns its readings from a source of monotonic time when it is available in a target platform,
|
||||
* and resorts to a non-monotonic time source otherwise.
|
||||
*/
|
||||
public object Monotonic : TimeSource by MonotonicTimeSource {
|
||||
public object Monotonic : TimeSource {
|
||||
override fun markNow(): DefaultTimeMark = MonotonicTimeSource.markNow()
|
||||
override fun toString(): String = MonotonicTimeSource.toString()
|
||||
}
|
||||
|
||||
@@ -46,7 +49,7 @@ public interface TimeSource {
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
public abstract class TimeMark {
|
||||
public interface TimeMark {
|
||||
/**
|
||||
* Returns the amount of time passed from this mark measured with the time source from which this mark was taken.
|
||||
*
|
||||
@@ -86,6 +89,28 @@ public abstract class TimeMark {
|
||||
public fun hasNotPassedNow(): Boolean = elapsedNow().isNegative()
|
||||
}
|
||||
|
||||
/**
|
||||
* A specialized [TimeMark] returned by [TimeSource.Monotonic].
|
||||
*
|
||||
* This time mark is implemented as an inline value class wrapping a platform-dependent
|
||||
* time reading value of the default monotonic time source, thus allowing to avoid additional boxing
|
||||
* of that value.
|
||||
*
|
||||
* The operations [plus] and [minus] are also specialized to return [DefaultTimeMark] type.
|
||||
*/
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.7")
|
||||
@JvmInline
|
||||
public value class DefaultTimeMark internal constructor(internal val reading: DefaultTimeMarkReading) : TimeMark {
|
||||
override fun elapsedNow(): Duration = MonotonicTimeSource.elapsedFrom(this)
|
||||
override fun plus(duration: Duration): DefaultTimeMark = MonotonicTimeSource.adjustReading(this, duration)
|
||||
override fun minus(duration: Duration): DefaultTimeMark = MonotonicTimeSource.adjustReading(this, -duration)
|
||||
override fun hasPassedNow(): Boolean = !elapsedNow().isNegative()
|
||||
override fun hasNotPassedNow(): Boolean = elapsedNow().isNegative()
|
||||
}
|
||||
|
||||
internal expect class DefaultTimeMarkReading
|
||||
|
||||
|
||||
@ExperimentalTime
|
||||
@SinceKotlin("1.3")
|
||||
@@ -109,7 +134,7 @@ public inline operator fun TimeMark.compareTo(other: TimeMark): Int = throw Erro
|
||||
|
||||
|
||||
@ExperimentalTime
|
||||
private class AdjustedTimeMark(val mark: TimeMark, val adjustment: Duration) : TimeMark() {
|
||||
private class AdjustedTimeMark(val mark: TimeMark, val adjustment: Duration) : TimeMark {
|
||||
override fun elapsedNow(): Duration = mark.elapsedNow() - adjustment
|
||||
|
||||
override fun plus(duration: Duration): TimeMark = AdjustedTimeMark(mark, adjustment + duration)
|
||||
|
||||
@@ -7,7 +7,11 @@ package kotlin.time
|
||||
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalTime
|
||||
internal expect object MonotonicTimeSource : TimeSource
|
||||
internal expect object MonotonicTimeSource : TimeSource {
|
||||
override fun markNow(): DefaultTimeMark
|
||||
fun elapsedFrom(timeMark: DefaultTimeMark): Duration
|
||||
fun adjustReading(timeMark: DefaultTimeMark, duration: Duration): DefaultTimeMark
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class used to implement time sources that return their readings as [Long] values in the specified [unit].
|
||||
@@ -23,7 +27,7 @@ public abstract class AbstractLongTimeSource(protected val unit: DurationUnit) :
|
||||
*/
|
||||
protected abstract fun read(): Long
|
||||
|
||||
private class LongTimeMark(private val startedAt: Long, private val timeSource: AbstractLongTimeSource, private val offset: Duration) : TimeMark() {
|
||||
private class LongTimeMark(private val startedAt: Long, private val timeSource: AbstractLongTimeSource, private val offset: Duration) : TimeMark {
|
||||
override fun elapsedNow(): Duration = (timeSource.read() - startedAt).toDuration(timeSource.unit) - offset
|
||||
override fun plus(duration: Duration): TimeMark = LongTimeMark(startedAt, timeSource, offset + duration)
|
||||
}
|
||||
@@ -45,7 +49,7 @@ public abstract class AbstractDoubleTimeSource(protected val unit: DurationUnit)
|
||||
*/
|
||||
protected abstract fun read(): Double
|
||||
|
||||
private class DoubleTimeMark(private val startedAt: Double, private val timeSource: AbstractDoubleTimeSource, private val offset: Duration) : TimeMark() {
|
||||
private class DoubleTimeMark(private val startedAt: Double, private val timeSource: AbstractDoubleTimeSource, private val offset: Duration) : TimeMark {
|
||||
override fun elapsedNow(): Duration = (timeSource.read() - startedAt).toDuration(timeSource.unit) - offset
|
||||
override fun plus(duration: Duration): TimeMark = DoubleTimeMark(startedAt, timeSource, offset + duration)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -39,6 +39,23 @@ public inline fun TimeSource.measureTime(block: () -> Unit): Duration {
|
||||
return mark.elapsedNow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given function [block] and returns the duration of elapsed time interval.
|
||||
*
|
||||
* The elapsed time is measured with the specified `this` [TimeSource.Monotonic] instance.
|
||||
*/
|
||||
@SinceKotlin("1.7")
|
||||
@ExperimentalTime
|
||||
public inline fun TimeSource.Monotonic.measureTime(block: () -> Unit): Duration {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
|
||||
val mark = markNow()
|
||||
block()
|
||||
return mark.elapsedNow()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Data class representing a result of executing an action, along with the duration of elapsed time interval.
|
||||
@@ -83,3 +100,21 @@ public inline fun <T> TimeSource.measureTimedValue(block: () -> T): TimedValue<T
|
||||
val result = block()
|
||||
return TimedValue(result, mark.elapsedNow())
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given [block] and returns an instance of [TimedValue] class, containing both
|
||||
* the result of function execution and the duration of elapsed time interval.
|
||||
*
|
||||
* The elapsed time is measured with the specified `this` [TimeSource.Monotonic] instance.
|
||||
*/
|
||||
@SinceKotlin("1.7")
|
||||
@ExperimentalTime
|
||||
public inline fun <T> TimeSource.Monotonic.measureTimedValue(block: () -> T): TimedValue<T> {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
|
||||
val mark = markNow()
|
||||
val result = block()
|
||||
return TimedValue(result, mark.elapsedNow())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user