Explicit public visibility, SinceKotlin and ExperimentalTime status

Use file level ExperimentalTime opt-in in tests.
This commit is contained in:
Ilya Gorbunov
2019-06-16 01:07:21 +03:00
parent 16111ab79f
commit c66740a7ed
14 changed files with 214 additions and 66 deletions
@@ -5,7 +5,8 @@
package kotlin.time
@SinceKotlin("1.3")
@ExperimentalTime
public actual enum class DurationUnit(internal val scale: Double) {
/**
* Time unit representing one nanosecond, which is 1/1000 of a microsecond.
@@ -37,6 +38,8 @@ public actual enum class DurationUnit(internal val scale: Double) {
DAYS(86400e9);
}
@SinceKotlin("1.3")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double {
val sourceCompareTarget = sourceUnit.scale.compareTo(targetUnit.scale)
return when {
@@ -8,6 +8,8 @@ package kotlin.time
import org.w3c.performance.GlobalPerformance
import org.w3c.performance.Performance
@SinceKotlin("1.3")
@ExperimentalTime
public actual object MonoClock : Clock {
private val actualClock: Clock = run {
@@ -28,6 +30,8 @@ internal external interface Process {
fun hrtime(time: Array<Double> = definedExternally): Array<Double>
}
@SinceKotlin("1.3")
@ExperimentalTime
internal class HrTimeClock(val process: Process) : Clock {
override fun mark(): ClockMark = object : ClockMark() {
@@ -39,11 +43,15 @@ internal class HrTimeClock(val process: Process) : Clock {
override fun toString(): String = "Clock(process.hrtime())"
}
@SinceKotlin("1.3")
@ExperimentalTime
internal class PerformanceClock(val performance: Performance) : AbstractDoubleClock(unit = DurationUnit.MILLISECONDS) {
override fun read(): Double = performance.now()
override fun toString(): String = "Clock(self.performance.now())"
}
@SinceKotlin("1.3")
@ExperimentalTime
internal object DateNowClock : AbstractDoubleClock(unit = DurationUnit.MILLISECONDS) {
override fun read(): Double = kotlin.js.Date.now()
override fun toString(): String = "Clock(Date.now())"
@@ -8,8 +8,12 @@
package kotlin.time
@SinceKotlin("1.3")
@ExperimentalTime
public actual typealias DurationUnit = java.util.concurrent.TimeUnit
@SinceKotlin("1.3")
@ExperimentalTime
internal actual fun convertDurationUnit(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double {
val sourceInTargets = targetUnit.convert(1, sourceUnit)
if (sourceInTargets > 0)
@@ -5,6 +5,8 @@
package kotlin.time
@SinceKotlin("1.3")
@ExperimentalTime
public actual object MonoClock : AbstractLongClock(unit = DurationUnit.NANOSECONDS), Clock { // TODO: interface should not be required here
override fun read(): Long = System.nanoTime()
override fun toString(): String = "Clock(System.nanoTime())"
+9 -5
View File
@@ -13,39 +13,43 @@ package kotlin.time
* @see [measureTime]
* @see [measureTimedValue]
*/
@SinceKotlin("1.3")
@ExperimentalTime
public interface Clock {
/**
* Marks a time point on this clock.
*/
fun mark(): ClockMark
public 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]).
*/
@SinceKotlin("1.3")
@ExperimentalTime
public abstract class ClockMark {
/**
* Returns the amount of time passed from this clock mark on the clock from which this mark was taken.
*/
abstract fun elapsed(): Duration
public abstract 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.
*/
open operator fun plus(duration: Duration): ClockMark = AdjustedClockMark(this, duration)
public open 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.
*/
open operator fun minus(duration: Duration): ClockMark = plus(-duration)
public open operator fun minus(duration: Duration): ClockMark = plus(-duration)
}
@ExperimentalTime
private class AdjustedClockMark(val mark: ClockMark, val adjustment: Duration) : ClockMark() {
override fun elapsed(): Duration = mark.elapsed() - adjustment
+9 -1
View File
@@ -10,11 +10,15 @@ import kotlin.js.JsName
/**
* The most precise clock available in the platform, whose readings increase monotonically over time.
*/
@SinceKotlin("1.3")
@ExperimentalTime
public expect object MonoClock : Clock
/**
* An abstract class used to implement clocks that return their readings as [Long] values in the specified [unit].
*/
@SinceKotlin("1.3")
@ExperimentalTime
public abstract class AbstractLongClock(protected val unit: DurationUnit) : Clock {
protected abstract fun read(): Long
@@ -29,6 +33,8 @@ public abstract class AbstractLongClock(protected val unit: DurationUnit) : Cloc
/**
* An abstract class used to implement clocks that return their readings as [Double] values in the specified [unit].
*/
@SinceKotlin("1.3")
@ExperimentalTime
public abstract class AbstractDoubleClock(protected val unit: DurationUnit) : Clock {
protected abstract fun read(): Double
@@ -43,9 +49,11 @@ public abstract class AbstractDoubleClock(protected val unit: DurationUnit) : Cl
/**
* A clock, whose readings can be preset and changed manually. It is useful as a predictable source of time in tests.
*/
@SinceKotlin("1.3")
@ExperimentalTime
public class TestClock(
@JsName("readingValue")
var reading: Long = 0L,
public var reading: Long = 0L,
unit: DurationUnit = DurationUnit.NANOSECONDS
) : AbstractLongClock(unit) {
override fun read(): Long = reading
+122 -57
View File
@@ -7,6 +7,7 @@ package kotlin.time
import kotlin.math.abs
@UseExperimental(ExperimentalTime::class)
private val storageUnit = DurationUnit.NANOSECONDS
/**
@@ -23,6 +24,8 @@ private val storageUnit = DurationUnit.NANOSECONDS
* use the functions [toInt], [toLong] and [toDouble]
* or the properties [inHours], [inMinutes], [inSeconds], [inNanoseconds] and so on.
*/
@SinceKotlin("1.3")
@ExperimentalTime
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
public inline class Duration internal constructor(internal val value: Double) : Comparable<Duration> {
// TODO: backend fails on init block, wait for KT-28055
@@ -32,8 +35,8 @@ public inline class Duration internal constructor(internal val value: Double) :
// }
companion object {
val ZERO: Duration = Duration(0.0)
val INFINITE: Duration = Duration(Double.POSITIVE_INFINITY)
public val ZERO: Duration = Duration(0.0)
public val INFINITE: Duration = Duration(Double.POSITIVE_INFINITY)
/** Converts the given time duration [value] expressed in the specified [sourceUnit] into the specified [targetUnit]. */
public fun convert(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double =
@@ -42,25 +45,25 @@ public inline class Duration internal constructor(internal val value: Double) :
// arithmetic operators
operator fun unaryMinus(): Duration = Duration(-value)
operator fun plus(other: Duration): Duration = Duration(value + other.value)
operator fun minus(other: Duration): Duration = Duration(value - other.value)
public operator fun unaryMinus(): Duration = Duration(-value)
public operator fun plus(other: Duration): Duration = Duration(value + other.value)
public operator fun minus(other: Duration): Duration = Duration(value - other.value)
// should we declare symmetric extension operators?
operator fun times(scale: Int): Duration = Duration(value * scale)
operator fun times(scale: Double): Duration = Duration(value * scale)
public operator fun times(scale: Int): Duration = Duration(value * scale)
public operator fun times(scale: Double): Duration = Duration(value * scale)
operator fun div(scale: Int): Duration = Duration(value / scale)
operator fun div(scale: Double): Duration = Duration(value / scale)
public operator fun div(scale: Int): Duration = Duration(value / scale)
public operator fun div(scale: Double): Duration = Duration(value / scale)
operator fun div(other: Duration): Double = this.value / other.value
public operator fun div(other: Duration): Double = this.value / other.value
fun isNegative(): Boolean = value < 0
fun isInfinite(): Boolean = value.isInfinite()
fun isFinite(): Boolean = value.isFinite()
public fun isNegative(): Boolean = value < 0
public fun isInfinite(): Boolean = value.isInfinite()
public fun isFinite(): Boolean = value.isFinite()
val absoluteValue: Duration get() = if (isNegative()) -this else this
public val absoluteValue: Duration get() = if (isNegative()) -this else this
override fun compareTo(other: Duration): Int = this.value.compareTo(other.value)
@@ -68,16 +71,16 @@ public inline class Duration internal constructor(internal val value: Double) :
// splitting to components
inline fun <T> toComponents(action: (days: Int, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T =
public inline fun <T> toComponents(action: (days: Int, hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T =
action(inDays.toInt(), hoursComponent, minutesComponent, secondsComponent, nanosecondsComponent)
inline fun <T> toComponents(action: (hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T =
public inline fun <T> toComponents(action: (hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -> T): T =
action(inHours.toInt(), minutesComponent, secondsComponent, nanosecondsComponent)
inline fun <T> toComponents(action: (minutes: Int, seconds: Int, nanoseconds: Int) -> T): T =
public inline fun <T> toComponents(action: (minutes: Int, seconds: Int, nanoseconds: Int) -> T): T =
action(inMinutes.toInt(), secondsComponent, nanosecondsComponent)
inline fun <T> toComponents(action: (seconds: Long, nanoseconds: Int) -> T): T =
public inline fun <T> toComponents(action: (seconds: Long, nanoseconds: Int) -> T): T =
action(inSeconds.toLong(), nanosecondsComponent)
@PublishedApi
@@ -92,24 +95,24 @@ public inline class Duration internal constructor(internal val value: Double) :
// conversion to units
fun toDouble(unit: DurationUnit): Double = convertDurationUnit(value, storageUnit, unit)
fun toLong(unit: DurationUnit): Long = toDouble(unit).toLong()
fun toInt(unit: DurationUnit): Int = toDouble(unit).toInt()
public fun toDouble(unit: DurationUnit): Double = convertDurationUnit(value, storageUnit, unit)
public fun toLong(unit: DurationUnit): Long = toDouble(unit).toLong()
public fun toInt(unit: DurationUnit): Int = toDouble(unit).toInt()
// option 1: in- properties
val inDays: Double get() = toDouble(DurationUnit.DAYS)
val inHours: Double get() = toDouble(DurationUnit.HOURS)
val inMinutes: Double get() = toDouble(DurationUnit.MINUTES)
val inSeconds: Double get() = toDouble(DurationUnit.SECONDS)
val inMilliseconds: Double get() = toDouble(DurationUnit.MILLISECONDS)
val inMicroseconds: Double get() = toDouble(DurationUnit.MICROSECONDS)
val inNanoseconds: Double get() = toDouble(DurationUnit.NANOSECONDS)
public val inDays: Double get() = toDouble(DurationUnit.DAYS)
public val inHours: Double get() = toDouble(DurationUnit.HOURS)
public val inMinutes: Double get() = toDouble(DurationUnit.MINUTES)
public val inSeconds: Double get() = toDouble(DurationUnit.SECONDS)
public val inMilliseconds: Double get() = toDouble(DurationUnit.MILLISECONDS)
public val inMicroseconds: Double get() = toDouble(DurationUnit.MICROSECONDS)
public val inNanoseconds: Double get() = toDouble(DurationUnit.NANOSECONDS)
// shortcuts
fun toLongNanoseconds(): Long = toLong(DurationUnit.NANOSECONDS)
fun toLongMilliseconds(): Long = toLong(DurationUnit.MILLISECONDS)
public fun toLongNanoseconds(): Long = toLong(DurationUnit.NANOSECONDS)
public fun toLongMilliseconds(): Long = toLong(DurationUnit.MILLISECONDS)
override fun toString(): String = buildString {
if (isInfinite()) {
@@ -147,14 +150,14 @@ public inline class Duration internal constructor(internal val value: Double) :
else -> 0
}
fun toString(unit: DurationUnit, decimals: Int = 0): String {
public fun toString(unit: DurationUnit, decimals: Int = 0): String {
require(decimals >= 0) { "decimals must be not negative, but was $decimals" }
if (isInfinite()) return value.toString()
return formatToExactDecimals(toDouble(unit), decimals) + unit.shortName()
}
fun toIsoString(): String = buildString {
public fun toIsoString(): String = buildString {
if (isNegative()) append('-')
append("PT")
absoluteValue.toComponents { hours, minutes, seconds, nanoseconds ->
@@ -183,47 +186,109 @@ public inline class Duration internal constructor(internal val value: Double) :
}
}
}
// constructing from number of units
// extension functions
fun Int.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
fun Long.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
fun Double.toDuration(unit: DurationUnit): Duration = Duration(convertDurationUnit(this, unit, storageUnit))
@SinceKotlin("1.3")
@ExperimentalTime
public fun Int.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
@SinceKotlin("1.3")
@ExperimentalTime
public fun Long.toDuration(unit: DurationUnit): Duration = toDouble().toDuration(unit)
@SinceKotlin("1.3")
@ExperimentalTime
public fun Double.toDuration(unit: DurationUnit): Duration = Duration(convertDurationUnit(this, unit, storageUnit))
// constructing from number of units
// extension properties
val Int.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
val Long.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
val Double.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
val Int.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
val Long.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
val Double.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
val Int.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
val Long.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
val Double.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.nanoseconds get() = toDuration(DurationUnit.NANOSECONDS)
val Int.seconds get() = toDuration(DurationUnit.SECONDS)
val Long.seconds get() = toDuration(DurationUnit.SECONDS)
val Double.seconds get() = toDuration(DurationUnit.SECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
val Int.minutes get() = toDuration(DurationUnit.MINUTES)
val Long.minutes get() = toDuration(DurationUnit.MINUTES)
val Double.minutes get() = toDuration(DurationUnit.MINUTES)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
val Int.hours get() = toDuration(DurationUnit.HOURS)
val Long.hours get() = toDuration(DurationUnit.HOURS)
val Double.hours get() = toDuration(DurationUnit.HOURS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.microseconds get() = toDuration(DurationUnit.MICROSECONDS)
val Int.days get() = toDuration(DurationUnit.DAYS)
val Long.days get() = toDuration(DurationUnit.DAYS)
val Double.days get() = toDuration(DurationUnit.DAYS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.milliseconds get() = toDuration(DurationUnit.MILLISECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.seconds get() = toDuration(DurationUnit.SECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.seconds get() = toDuration(DurationUnit.SECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.seconds get() = toDuration(DurationUnit.SECONDS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.minutes get() = toDuration(DurationUnit.MINUTES)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.minutes get() = toDuration(DurationUnit.MINUTES)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.minutes get() = toDuration(DurationUnit.MINUTES)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.hours get() = toDuration(DurationUnit.HOURS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.hours get() = toDuration(DurationUnit.HOURS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.hours get() = toDuration(DurationUnit.HOURS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Int.days get() = toDuration(DurationUnit.DAYS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Long.days get() = toDuration(DurationUnit.DAYS)
@SinceKotlin("1.3")
@ExperimentalTime
public val Double.days get() = toDuration(DurationUnit.DAYS)
internal expect fun formatToExactDecimals(value: Double, decimals: Int): String
@@ -14,6 +14,8 @@ package kotlin.time
*
* The smallest time unit is [NANOSECONDS] and the largest is [DAYS], which corresponds to exactly 24 [HOURS].
*/
@SinceKotlin("1.3")
@ExperimentalTime
public expect enum class DurationUnit {
/**
* Time unit representing one nanosecond, which is 1/1000 of a microsecond.
@@ -46,10 +48,13 @@ public expect enum class DurationUnit {
}
/** Converts the given time duration [value] expressed in the specified [sourceUnit] into the specified [targetUnit]. */
@SinceKotlin("1.3")
@ExperimentalTime
internal expect fun convertDurationUnit(value: Double, sourceUnit: DurationUnit, targetUnit: DurationUnit): Double
@SinceKotlin("1.3")
@ExperimentalTime
internal fun DurationUnit.shortName(): String = when (this) {
DurationUnit.NANOSECONDS -> "ns"
DurationUnit.MICROSECONDS -> "us"
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2019 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.
*/
package kotlin.time
import kotlin.annotation.AnnotationTarget.*
/**
* This annotation marks the experimental standard library API for measuring time and working with durations.
*
* > Beware using the annotated API especially if you're developing a library, since your library might become binary incompatible
* with the future versions of the standard library.
*
* Any usage of a declaration annotated with `@ExperimentalTime` must be accepted either by
* annotating that usage with the [UseExperimental] annotation, e.g. `@UseExperimental(ExperimentalTime::class)`,
* or by using the compiler argument `-Xuse-experimental=kotlin.time.ExperimentalTime`.
*/
@Experimental(level = Experimental.Level.ERROR)
@Retention(AnnotationRetention.BINARY)
@Target(
CLASS,
ANNOTATION_CLASS,
PROPERTY,
FIELD,
LOCAL_VARIABLE,
VALUE_PARAMETER,
CONSTRUCTOR,
FUNCTION,
PROPERTY_GETTER,
PROPERTY_SETTER,
TYPEALIAS
)
@SinceKotlin("1.3")
public annotation class ExperimentalTime
@@ -12,6 +12,8 @@ import kotlin.contracts.*
*
* The elapsed time is measured with [MonoClock].
*/
@SinceKotlin("1.3")
@ExperimentalTime
public inline fun measureTime(block: () -> Unit): Duration {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@@ -25,6 +27,8 @@ public inline fun measureTime(block: () -> Unit): Duration {
*
* The elapsed time is measured with the specified `this` [Clock] instance.
*/
@SinceKotlin("1.3")
@ExperimentalTime
public inline fun Clock.measureTime(block: () -> Unit): Duration {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@@ -42,6 +46,8 @@ public inline fun Clock.measureTime(block: () -> Unit): Duration {
* @property value the result of the action.
* @property duration the time elapsed to execute the action.
*/
@SinceKotlin("1.3")
@ExperimentalTime
public data class TimedValue<T>(val value: T, val duration: Duration)
/**
@@ -50,6 +56,8 @@ public data class TimedValue<T>(val value: T, val duration: Duration)
*
* The elapsed time is measured with [MonoClock].
*/
@SinceKotlin("1.3")
@ExperimentalTime
public inline fun <T> measureTimedValue(block: () -> T): TimedValue<T> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@@ -64,6 +72,8 @@ public inline fun <T> measureTimedValue(block: () -> T): TimedValue<T> {
*
* The elapsed time is measured with the specified `this` [Clock] instance.
*/
@SinceKotlin("1.3")
@ExperimentalTime
public inline fun <T> Clock.measureTimedValue(block: () -> T): TimedValue<T> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
+1 -1
View File
@@ -2,7 +2,7 @@
* Copyright 2010-2019 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.
*/
@file:UseExperimental(ExperimentalTime::class)
package test.time
import kotlin.test.*
@@ -3,6 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:UseExperimental(ExperimentalTime::class)
package test.time
import test.numbers.assertAlmostEquals
@@ -3,6 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:UseExperimental(ExperimentalTime::class)
package test.time
import kotlin.test.*
@@ -3,6 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:UseExperimental(ExperimentalTime::class)
package test.time
import kotlin.random.Random