summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland <rk@rkuhn.info>2012-09-07 21:35:17 +0200
committerRoland <rk@rkuhn.info>2012-09-07 21:35:17 +0200
commitf41d3ade90c3cfee772b6475eca7350883b81e2c (patch)
tree25f735a5fe90304c235ca098a229265e12291381
parent7a833f94296849c0e2a6cbacb7e513599c831f38 (diff)
downloadscala-f41d3ade90c3cfee772b6475eca7350883b81e2c.tar.gz
scala-f41d3ade90c3cfee772b6475eca7350883b81e2c.tar.bz2
scala-f41d3ade90c3cfee772b6475eca7350883b81e2c.zip
fix some one more issue in Duration
- Inf / Zero == Inf - add some more missing test cases - clarify magic constant - move exception descriptions into proper @throws docs
-rw-r--r--src/library/scala/concurrent/util/Duration.scala133
-rw-r--r--test/files/jvm/duration-tck.scala18
2 files changed, 91 insertions, 60 deletions
diff --git a/src/library/scala/concurrent/util/Duration.scala b/src/library/scala/concurrent/util/Duration.scala
index c0eccec4db..391549ef72 100644
--- a/src/library/scala/concurrent/util/Duration.scala
+++ b/src/library/scala/concurrent/util/Duration.scala
@@ -97,9 +97,9 @@ object Duration {
* - the unit is NANOSECONDS
* - and the length has an absolute value greater than 2^53
*
- * Will throw an exception if the length was finite but the resulting duration cannot be expressed
- * as a [[FiniteDuration]]. Infinite inputs (and NaN) are converted into [[Duration.Inf]],
- * [[Duration.MinusInf]] and [[Duration.Undefined]], respectively.
+ * Infinite inputs (and NaN) are converted into [[Duration.Inf]], [[Duration.MinusInf]] and [[Duration.Undefined]], respectively.
+ *
+ * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]]
*/
def apply(length: Double, unit: TimeUnit): Duration = fromNanos(unit.toNanos(1) * length)
/**
@@ -116,11 +116,15 @@ object Duration {
*/
def apply(length: Long, unit: String): FiniteDuration = new FiniteDuration(length, Duration.timeUnit(unit))
+ // Double stores 52 bits mantissa, but there is an implied '1' in front, making the limit 2^53
+ final val maxPreciseDouble = 9007199254740992d
+
/**
* Parse String into Duration. Format is `"<length><unit>"`, where
* whitespace is allowed before, between and after the parts. Infinities are
* designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`.
- * Throws exception if format is not parseable.
+ *
+ * @throws NumberFormatException if format is not parseable
*/
def apply(s: String): Duration = {
val s1: String = s filterNot (_.isWhitespace)
@@ -133,9 +137,9 @@ object Duration {
case Some(unit) =>
val valueStr = s1 dropRight unitName.length
val valueD = JDouble.parseDouble(valueStr)
- if (valueD <= 9007199254740992d && valueD >= -9007199254740992d) Duration(valueD, unit)
+ if (valueD >= -maxPreciseDouble && valueD <= maxPreciseDouble) Duration(valueD, unit)
else Duration(JLong.parseLong(valueStr), unit)
- case _ => sys.error("format error " + s)
+ case _ => throw new NumberFormatException("format error " + s)
}
}
}
@@ -187,6 +191,8 @@ object Duration {
*
* The semantics of the resulting Duration objects matches the semantics of their Double
* counterparts with respect to arithmetic operations.
+ *
+ * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]]
*/
def fromNanos(nanos: Double): Duration = {
if (nanos.isInfinite)
@@ -207,10 +213,11 @@ object Duration {
private val d_per_ns = h_per_ns * 24
/**
- * Construct a finite duration from the given number of nanoseconds. This will throw an
- * exception for `Long.MinValue` since that would lead to inconsistent behavior afterwards
- * (cannot be negated). The result will have the coarsest possible time unit which can
- * exactly express this duration.
+ * Construct a finite duration from the given number of nanoseconds. The
+ * result will have the coarsest possible time unit which can exactly express
+ * this duration.
+ *
+ * @throws IllegalArgumentException for `Long.MinValue` since that would lead to inconsistent behavior afterwards (cannot be negated)
*/
def fromNanos(nanos: Long): FiniteDuration = {
if (nanos % d_per_ns == 0) Duration(nanos / d_per_ns, DAYS)
@@ -269,8 +276,8 @@ object Duration {
else if (factor < 0d) -this
else this
def /(factor: Double): Duration =
- if (factor == 0d || factor.isNaN || factor.isInfinite) Undefined
- else if (factor < 0d) -this
+ if (factor.isNaN || factor.isInfinite) Undefined
+ else if ((factor compare 0d) < 0) -this
else this
def /(other: Duration): Double = other match {
case _: Infinite => Double.NaN
@@ -314,10 +321,7 @@ object Duration {
*/
val MinusInf: Infinite = new Infinite {
override def toString = "Duration.MinusInf"
- def compare(other: Duration) = other match {
- case x if x eq this => 0
- case _ => -1
- }
+ def compare(other: Duration) = if (other eq this) 0 else -1
def unary_- : Duration = Inf
def toUnit(unit: TimeUnit): Double = Double.NegativeInfinity
}
@@ -335,9 +339,9 @@ object Duration {
* - the unit is NANOSECONDS
* - and the length has an absolute value greater than 2^53
*
- * Will throw an exception if the length was finite but the resulting duration cannot be expressed
- * as a [[FiniteDuration]]. Infinite inputs (and NaN) are converted into [[Duration.Inf]],
- * [[Duration.MinusInf]] and [[Duration.Undefined]], respectively.
+ * Infinite inputs (and NaN) are converted into [[Duration.Inf]], [[Duration.MinusInf]] and [[Duration.Undefined]], respectively.
+ *
+ * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]]
*/
def create(length: Double, unit: TimeUnit): Duration = apply(length, unit)
/**
@@ -352,7 +356,8 @@ object Duration {
* Parse String into Duration. Format is `"<length><unit>"`, where
* whitespace is allowed before, between and after the parts. Infinities are
* designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`.
- * Throws exception if format is not parseable.
+ *
+ * @throws NumberFormatException if format is not parseable
*/
def create(s: String): Duration = apply(s)
@@ -428,43 +433,63 @@ object Duration {
* The default ordering is consistent with the ordering of Double numbers, which means that Undefined is
* considered greater than all other durations, including [[Duration.Inf]].
*
- * @define exc Invoking this method on a non-finite duration will result in an IllegalArgumentException.
+ * @define exc @throws IllegalArgumentException when invoked on a non-finite duration
+ *
+ * @define ovf @throws IllegalArgumentException in case of a finite overflow: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite durations takes place.
*/
sealed abstract class Duration extends Serializable with Ordered[Duration] {
/**
- * Obtain the length of this Duration measured in the unit obtained by the `unit` method. $exc
+ * Obtain the length of this Duration measured in the unit obtained by the `unit` method.
+ *
+ * $exc
*/
def length: Long
/**
- * Obtain the time unit in which the length of this duration is measured. $exc
+ * Obtain the time unit in which the length of this duration is measured.
+ *
+ * $exc
*/
def unit: TimeUnit
/**
- * Return the length of this duration measured in whole nanoseconds, rounding towards zero. $exc
+ * Return the length of this duration measured in whole nanoseconds, rounding towards zero.
+ *
+ * $exc
*/
def toNanos: Long
/**
- * Return the length of this duration measured in whole microseconds, rounding towards zero. $exc
+ * Return the length of this duration measured in whole microseconds, rounding towards zero.
+ *
+ * $exc
*/
def toMicros: Long
/**
- * Return the length of this duration measured in whole milliseconds, rounding towards zero. $exc
+ * Return the length of this duration measured in whole milliseconds, rounding towards zero.
+ *
+ * $exc
*/
def toMillis: Long
/**
- * Return the length of this duration measured in whole seconds, rounding towards zero. $exc
+ * Return the length of this duration measured in whole seconds, rounding towards zero.
+ *
+ * $exc
*/
def toSeconds: Long
/**
- * Return the length of this duration measured in whole minutes, rounding towards zero. $exc
+ * Return the length of this duration measured in whole minutes, rounding towards zero.
+ *
+ * $exc
*/
def toMinutes: Long
/**
- * Return the length of this duration measured in whole hours, rounding towards zero. $exc
+ * Return the length of this duration measured in whole hours, rounding towards zero.
+ *
+ * $exc
*/
def toHours: Long
/**
- * Return the length of this duration measured in whole days, rounding towards zero. $exc
+ * Return the length of this duration measured in whole days, rounding towards zero.
+ *
+ * $exc
*/
def toDays: Long
/**
@@ -478,31 +503,31 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] {
def toUnit(unit: TimeUnit): Double
/**
- * Return the sum of that duration and this. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite summands the semantics match those
+ * Return the sum of that duration and this. When involving non-finite summands the semantics match those
* of Double.
+ *
+ * $ovf
*/
def +(other: Duration): Duration
/**
- * Return the difference of that duration and this. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite summands the semantics match those
+ * Return the difference of that duration and this. When involving non-finite summands the semantics match those
* of Double.
+ *
+ * $ovf
*/
def -(other: Duration): Duration
/**
- * Return this duration multiplied by the scalar factor. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite factors the semantics match those
+ * Return this duration multiplied by the scalar factor. When involving non-finite factors the semantics match those
* of Double.
+ *
+ * $ovf
*/
def *(factor: Double): Duration
/**
- * Return this duration divided by the scalar factor. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite factors the semantics match those
+ * Return this duration divided by the scalar factor. When involving non-finite factors the semantics match those
* of Double.
+ *
+ * $ovf
*/
def /(factor: Double): Duration
/**
@@ -535,10 +560,10 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] {
// Java API
/**
- * Return this duration divided by the scalar factor. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite factors the semantics match those
+ * Return this duration divided by the scalar factor. When involving non-finite factors the semantics match those
* of Double.
+ *
+ * $ovf
*/
def div(factor: Double) = this / factor
/**
@@ -551,17 +576,17 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] {
def lt(other: Duration) = this < other
def lteq(other: Duration) = this <= other
/**
- * Return the difference of that duration and this. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite summands the semantics match those
+ * Return the difference of that duration and this. When involving non-finite summands the semantics match those
* of Double.
+ *
+ * $ovf
*/
def minus(other: Duration) = this - other
/**
- * Return this duration multiplied by the scalar factor. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite factors the semantics match those
+ * Return this duration multiplied by the scalar factor. When involving non-finite factors the semantics match those
* of Double.
+ *
+ * $ovf
*/
def mul(factor: Double) = this * factor
/**
@@ -569,10 +594,10 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] {
*/
def neg() = -this
/**
- * Return the sum of that duration and this. In case of an overflow, an IllegalArgumentException
- * is thrown: the range of a finite duration is +-(2^63-1)ns, and no conversion to infinite
- * durations takes place. When involving non-finite summands the semantics match those
+ * Return the sum of that duration and this. When involving non-finite summands the semantics match those
* of Double.
+ *
+ * $ovf
*/
def plus(other: Duration) = this + other
}
diff --git a/test/files/jvm/duration-tck.scala b/test/files/jvm/duration-tck.scala
index aa1ac50078..87ffa196ca 100644
--- a/test/files/jvm/duration-tck.scala
+++ b/test/files/jvm/duration-tck.scala
@@ -88,6 +88,7 @@ object Test extends App {
inputs filterNot (_.isFinite) foreach (x => x / zero mustBe x.toUnit(DAYS))
inputs filterNot (_.isFinite) foreach (_ * 0d mustBe undef)
+ inputs filterNot (_.isFinite) foreach (_ * -0d mustBe undef)
inputs filterNot (_.isFinite) foreach (x => x * Double.PositiveInfinity mustBe x)
inputs filterNot (_.isFinite) foreach (x => x * Double.NegativeInfinity mustBe -x)
@@ -112,7 +113,13 @@ object Test extends App {
inputs foreach (undef + _ mustBe undef)
inputs foreach (undef - _ mustBe undef)
inputs foreach (undef / _ mustBe nan)
- inputs filter (_.isFinite) foreach (x => x / zero mustBe x.toUnit(SECONDS) / 0d)
+ undef / 1 mustBe undef
+ undef / nan mustBe undef
+ undef * 1 mustBe undef
+ undef * nan mustBe undef
+ inputs foreach (x => x / zero mustBe x.toUnit(SECONDS) / 0d)
+ inputs foreach (x => x / 0d mustBe Duration.fromNanos(x.toUnit(NANOSECONDS) / 0d))
+ inputs foreach (x => x / -0d mustBe Duration.fromNanos(x.toUnit(NANOSECONDS) / -0d))
inputs filterNot (_ eq undef) foreach (_ compareTo undef mustBe -1)
inputs filterNot (_ eq undef) foreach (undef compareTo _ mustBe 1)
@@ -170,12 +177,11 @@ object Test extends App {
// test Deadline
val dead = 2.seconds.fromNow
val dead2 = 2 seconds fromNow
- // view bounds vs. very local type inference vs. operator precedence: sigh
- assert(dead.timeLeft > (1 second: Duration))
- assert(dead2.timeLeft > (1 second: Duration))
+ assert(dead.timeLeft > 1.second)
+ assert(dead2.timeLeft > 1.second)
Thread.sleep(1.second.toMillis)
- assert(dead.timeLeft < (1 second: Duration))
- assert(dead2.timeLeft < (1 second: Duration))
+ assert(dead.timeLeft < 1.second)
+ assert(dead2.timeLeft < 1.second)
// check statically retaining finite-ness