Improve Duration classes
- add more factories and implicits (for Double) - add extractors for deconstruction and string parsing - fix bug in infinite durations (comparisons were inverted)
This commit is contained in:
parent
bcdb429573
commit
4e798047b8
1 changed files with 180 additions and 117 deletions
|
|
@ -5,16 +5,70 @@
|
|||
package akka.util
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import TimeUnit._
|
||||
import java.lang.{Long => JLong, Double => JDouble}
|
||||
|
||||
object Duration {
|
||||
def apply(length: Long, unit: TimeUnit) : Duration = new FiniteDuration(length, unit)
|
||||
def apply(length: Double, unit: TimeUnit) : Duration = new FiniteDuration(length, unit)
|
||||
def apply(length: Long, unit: String) : Duration = new FiniteDuration(length, timeUnit(unit))
|
||||
|
||||
/**
|
||||
* Construct a Duration by parsing a String. In case of a format error, a
|
||||
* RuntimeException is thrown. See `unapply(String)` for more information.
|
||||
*/
|
||||
def apply(s : String) : Duration = unapply(s) getOrElse error("format error")
|
||||
|
||||
/**
|
||||
* Deconstruct a Duration into length and unit if it is finite.
|
||||
*/
|
||||
def unapply(d : Duration) : Option[(Long, TimeUnit)] = {
|
||||
if (d.finite_?) {
|
||||
Some((d.length, d.unit))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
private val RE = ("""^\s*(\d+(?:\.\d+)?)\s*"""+ // length part
|
||||
"(?:"+ // units are distinguished in separate match groups
|
||||
"(h|hour|hours)|"+
|
||||
"(min|minute|minutes)|"+
|
||||
"(s|sec|second|seconds)|"+
|
||||
"(ms|milli|millis|millisecond|milliseconds)|"+
|
||||
"(µs|micro|micros|microsecond|microseconds)|"+
|
||||
"(ns|nano|nanos|nanosecond|nanoseconds)"+
|
||||
""")\s*$""").r // close the non-capturing group
|
||||
private val REinf = """^\s*Inf\s*$""".r
|
||||
private val REminf = """^\s*(?:-\s*|Minus)Inf\s*""".r
|
||||
|
||||
/**
|
||||
* Parse String, return None if no match. Format is `"<length><unit>"`, where
|
||||
* whitespace is allowed before, between and after the parts. Infinities are
|
||||
* designated by `"Inf"` and `"-Inf"` or `"MinusInf"`.
|
||||
*/
|
||||
def unapply(s : String) : Option[Duration] = s match {
|
||||
case RE(length, h, m, s, ms, mus, ns) =>
|
||||
if (h ne null) Some(Duration(3600 * JDouble.parseDouble(length), SECONDS)) else
|
||||
if (m ne null) Some(Duration(60 * JDouble.parseDouble(length), SECONDS)) else
|
||||
if (s ne null) Some(Duration(1 * JDouble.parseDouble(length), SECONDS)) else
|
||||
if (ms ne null) Some(Duration(1 * JDouble.parseDouble(length), MILLISECONDS)) else
|
||||
if (mus ne null) Some(Duration(1 * JDouble.parseDouble(length), MICROSECONDS)) else
|
||||
if (ns ne null) Some(Duration(1 * JDouble.parseDouble(length), NANOSECONDS)) else
|
||||
error("made some error in regex (should not be possible)")
|
||||
case REinf() => Some(Inf)
|
||||
case REminf() => Some(MinusInf)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse TimeUnit from string representation.
|
||||
*/
|
||||
def timeUnit(unit: String) = unit.toLowerCase match {
|
||||
case "nanoseconds" | "nanos" | "nanosecond" | "nano" => TimeUnit.NANOSECONDS
|
||||
case "microseconds" | "micros" | "microsecond" | "micro" => TimeUnit.MICROSECONDS
|
||||
case "milliseconds" | "millis" | "millisecond" | "milli" => TimeUnit.MILLISECONDS
|
||||
case _ => TimeUnit.SECONDS
|
||||
case "nanoseconds" | "nanos" | "nanosecond" | "nano" => NANOSECONDS
|
||||
case "microseconds" | "micros" | "microsecond" | "micro" => MICROSECONDS
|
||||
case "milliseconds" | "millis" | "millisecond" | "milli" => MILLISECONDS
|
||||
case _ => SECONDS
|
||||
}
|
||||
|
||||
trait Infinite {
|
||||
|
|
@ -29,30 +83,38 @@ object Duration {
|
|||
|
||||
def finite_? = false
|
||||
|
||||
def length : Long = error("length not allowed on infinite Durations")
|
||||
def unit : TimeUnit = error("unit not allowed on infinite Durations")
|
||||
def toNanos : Long = error("toNanos not allowed on infinite Durations")
|
||||
def toMicros : Long = error("toMicros not allowed on infinite Durations")
|
||||
def toMillis : Long = error("toMillis not allowed on infinite Durations")
|
||||
def toSeconds : Long = error("toSeconds not allowed on infinite Durations")
|
||||
def length : Long = throw new IllegalArgumentException("length not allowed on infinite Durations")
|
||||
def unit : TimeUnit = throw new IllegalArgumentException("unit not allowed on infinite Durations")
|
||||
def toNanos : Long = throw new IllegalArgumentException("toNanos not allowed on infinite Durations")
|
||||
def toMicros : Long = throw new IllegalArgumentException("toMicros not allowed on infinite Durations")
|
||||
def toMillis : Long = throw new IllegalArgumentException("toMillis not allowed on infinite Durations")
|
||||
def toSeconds : Long = throw new IllegalArgumentException("toSeconds not allowed on infinite Durations")
|
||||
}
|
||||
|
||||
/**
|
||||
* Infinite duration: greater than any other and not equal to any other,
|
||||
* including itself.
|
||||
*/
|
||||
object Inf extends Duration with Infinite {
|
||||
override def toString = "Duration.Inf"
|
||||
def >(other : Duration) = false
|
||||
def >=(other : Duration) = false
|
||||
def <(other : Duration) = true
|
||||
def <=(other : Duration) = true
|
||||
def unary_- : Duration = MinusInf
|
||||
}
|
||||
|
||||
object MinusInf extends Duration with Infinite {
|
||||
override def toString = "Duration.MinusInf"
|
||||
def >(other : Duration) = true
|
||||
def >=(other : Duration) = true
|
||||
def <(other : Duration) = false
|
||||
def <=(other : Duration) = false
|
||||
def unary_- : Duration = MinusInf
|
||||
}
|
||||
|
||||
/**
|
||||
* Infinite negative duration: lesser than any other and not equal to any other,
|
||||
* including itself.
|
||||
*/
|
||||
object MinusInf extends Duration with Infinite {
|
||||
override def toString = "Duration.MinusInf"
|
||||
def >(other : Duration) = false
|
||||
def >=(other : Duration) = false
|
||||
def <(other : Duration) = true
|
||||
def <=(other : Duration) = true
|
||||
def unary_- : Duration = Inf
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -66,7 +128,7 @@ object Duration {
|
|||
* import akka.util.Duration;
|
||||
* import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* Duration duration = new Duration(100, TimeUnit.MILLISECONDS);
|
||||
* Duration duration = new Duration(100, MILLISECONDS);
|
||||
* Duration duration = new Duration(5, "seconds");
|
||||
*
|
||||
* duration.toNanos();
|
||||
|
|
@ -78,18 +140,28 @@ object Duration {
|
|||
* import akka.util.Duration
|
||||
* import java.util.concurrent.TimeUnit
|
||||
*
|
||||
* val duration = Duration(100, TimeUnit.MILLISECONDS)
|
||||
* val duration = Duration(100, MILLISECONDS)
|
||||
* val duration = Duration(100, "millis")
|
||||
*
|
||||
* duration.toNanos
|
||||
* duration < 1.second
|
||||
* duration <= Duration.Inf
|
||||
* </pre>
|
||||
*
|
||||
* <p/>
|
||||
* Implicits are also provided for Int and Long. Example usage:
|
||||
* Implicits are also provided for Int, Long and Double. Example usage:
|
||||
* <pre>
|
||||
* import akka.util.duration._
|
||||
*
|
||||
* val duration = 100.millis
|
||||
* val duration = 100 millis
|
||||
* </pre>
|
||||
*
|
||||
* Extractors, parsing and arithmetic are also included:
|
||||
* <pre>
|
||||
* val d = Duration("1.2 µs")
|
||||
* val Duration(length, unit) = 5 millis
|
||||
* val d2 = d * 2.5
|
||||
* val d3 = d2 + 1.millisecond
|
||||
* </pre>
|
||||
*/
|
||||
trait Duration {
|
||||
|
|
@ -113,11 +185,26 @@ trait Duration {
|
|||
|
||||
class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
|
||||
def this(length: Long, unit: String) = this(length, Duration.timeUnit(unit))
|
||||
def this(length: Double, unit: TimeUnit) = {
|
||||
this(1, unit)
|
||||
this * length
|
||||
}
|
||||
|
||||
def toNanos = unit.toNanos(length)
|
||||
def toMicros = unit.toMicros(length)
|
||||
def toMillis = unit.toMillis(length)
|
||||
def toSeconds = unit.toSeconds(length)
|
||||
override def toString = "Duration(" + length + ", " + unit + ")"
|
||||
|
||||
override def toString = this match {
|
||||
case Duration(1, SECONDS) => "1 second"
|
||||
case Duration(x, SECONDS) => x+" seconds"
|
||||
case Duration(1, MILLISECONDS) => "1 millisecond"
|
||||
case Duration(x, MILLISECONDS) => x+" milliseconds"
|
||||
case Duration(1, MICROSECONDS) => "1 microsecond"
|
||||
case Duration(x, MICROSECONDS) => x+" microseconds"
|
||||
case Duration(1, NANOSECONDS) => "1 nanosecond"
|
||||
case Duration(x, NANOSECONDS) => x+" nanoseconds"
|
||||
}
|
||||
|
||||
def <(other : Duration) = {
|
||||
if (other.finite_?) {
|
||||
|
|
@ -153,17 +240,17 @@ class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
|
|||
|
||||
private def fromNanos(nanos : Long) : Duration = {
|
||||
if (nanos % 1000000000L == 0) {
|
||||
Duration(nanos / 1000000000L, TimeUnit.SECONDS)
|
||||
Duration(nanos / 1000000000L, SECONDS)
|
||||
} else if (nanos % 1000000L == 0) {
|
||||
Duration(nanos / 1000000L, TimeUnit.MILLISECONDS)
|
||||
Duration(nanos / 1000000L, MILLISECONDS)
|
||||
} else if (nanos % 1000L == 0) {
|
||||
Duration(nanos / 1000L, TimeUnit.MICROSECONDS)
|
||||
Duration(nanos / 1000L, MICROSECONDS)
|
||||
} else {
|
||||
Duration(nanos, TimeUnit.NANOSECONDS)
|
||||
Duration(nanos, NANOSECONDS)
|
||||
}
|
||||
}
|
||||
|
||||
private def fromNanos(nanos : Double) : Duration = fromNanos(nanos.asInstanceOf[Long])
|
||||
private def fromNanos(nanos : Double) : Duration = fromNanos((nanos + 0.5).asInstanceOf[Long])
|
||||
|
||||
def +(other : Duration) = {
|
||||
if (!other.finite_?) {
|
||||
|
|
@ -198,61 +285,11 @@ class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
|
|||
override def hashCode = toNanos.asInstanceOf[Int]
|
||||
}
|
||||
|
||||
object Inf extends Duration {
|
||||
override def toString = "Duration.Inf"
|
||||
override def equals(other : Any) = false
|
||||
|
||||
def >(other : Duration) = true
|
||||
def >=(other : Duration) = true
|
||||
def <(other : Duration) = false
|
||||
def <=(other : Duration) = false
|
||||
|
||||
def +(other : Duration) : Duration = this
|
||||
def -(other : Duration) : Duration = this
|
||||
def *(other : Double) : Duration = this
|
||||
def /(other : Double) : Duration = this
|
||||
|
||||
def unary_- : Duration = MinusInf
|
||||
|
||||
def finite_? = false
|
||||
|
||||
def length : Long = error("length not allowed on Inf")
|
||||
def unit : TimeUnit = error("unit not allowed on Inf")
|
||||
def toNanos : Long = error("toNanos not allowed on Inf")
|
||||
def toMicros : Long = error("toMicros not allowed on Inf")
|
||||
def toMillis : Long = error("toMillis not allowed on Inf")
|
||||
def toSeconds : Long = error("toSeconds not allowed on Inf")
|
||||
}
|
||||
|
||||
object MinusInf extends Duration {
|
||||
override def toString = "Duration.MinusInf"
|
||||
override def equals(other : Any) = false
|
||||
|
||||
def >(other : Duration) = false
|
||||
def >=(other : Duration) = false
|
||||
def <(other : Duration) = true
|
||||
def <=(other : Duration) = true
|
||||
|
||||
def +(other : Duration) : Duration = this
|
||||
def -(other : Duration) : Duration = this
|
||||
def *(other : Double) : Duration = this
|
||||
def /(other : Double) : Duration = this
|
||||
|
||||
def unary_- : Duration = Inf
|
||||
|
||||
def finite_? = false
|
||||
|
||||
def length : Long = error("length not allowed on MinusInf")
|
||||
def unit : TimeUnit = error("unit not allowed on MinusInf")
|
||||
def toNanos : Long = error("toNanos not allowed on MinusInf")
|
||||
def toMicros : Long = error("toMicros not allowed on MinusInf")
|
||||
def toMillis : Long = error("toMillis not allowed on MinusInf")
|
||||
def toSeconds : Long = error("toSeconds not allowed on MinusInf")
|
||||
}
|
||||
|
||||
package object duration {
|
||||
implicit def intToDurationInt(n: Int) = new DurationInt(n)
|
||||
implicit def longToDurationLong(n: Long) = new DurationLong(n)
|
||||
implicit def doubleToDurationDouble(d: Double) = new DurationDouble(d)
|
||||
|
||||
implicit def pairIntToDuration(p : (Int, TimeUnit)) = Duration(p._1, p._2)
|
||||
implicit def pairLongToDuration(p : (Long, TimeUnit)) = Duration(p._1, p._2)
|
||||
implicit def durationToPair(d : Duration) = (d.length, d.unit)
|
||||
|
|
@ -266,53 +303,79 @@ package object duration {
|
|||
}
|
||||
|
||||
class DurationInt(n: Int) {
|
||||
def nanoseconds = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nanos = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nanosecond = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nano = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nanoseconds = Duration(n, NANOSECONDS)
|
||||
def nanos = Duration(n, NANOSECONDS)
|
||||
def nanosecond = Duration(n, NANOSECONDS)
|
||||
def nano = Duration(n, NANOSECONDS)
|
||||
|
||||
def microseconds = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def micros = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def microsecond = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def micro = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def microseconds = Duration(n, MICROSECONDS)
|
||||
def micros = Duration(n, MICROSECONDS)
|
||||
def microsecond = Duration(n, MICROSECONDS)
|
||||
def micro = Duration(n, MICROSECONDS)
|
||||
|
||||
def milliseconds = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def millis = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def millisecond = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def milli = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def milliseconds = Duration(n, MILLISECONDS)
|
||||
def millis = Duration(n, MILLISECONDS)
|
||||
def millisecond = Duration(n, MILLISECONDS)
|
||||
def milli = Duration(n, MILLISECONDS)
|
||||
|
||||
def seconds = Duration(n, TimeUnit.SECONDS)
|
||||
def second = Duration(n, TimeUnit.SECONDS)
|
||||
def seconds = Duration(n, SECONDS)
|
||||
def second = Duration(n, SECONDS)
|
||||
|
||||
def minutes = Duration(60 * n, TimeUnit.SECONDS)
|
||||
def minute = Duration(60 * n, TimeUnit.SECONDS)
|
||||
def minutes = Duration(60 * n, SECONDS)
|
||||
def minute = Duration(60 * n, SECONDS)
|
||||
|
||||
def hours = Duration(3600 * n, TimeUnit.SECONDS)
|
||||
def hour = Duration(3600 * n, TimeUnit.SECONDS)
|
||||
def hours = Duration(3600 * n, SECONDS)
|
||||
def hour = Duration(3600 * n, SECONDS)
|
||||
}
|
||||
|
||||
class DurationLong(n: Long) {
|
||||
def nanoseconds = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nanos = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nanosecond = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nano = Duration(n, TimeUnit.NANOSECONDS)
|
||||
def nanoseconds = Duration(n, NANOSECONDS)
|
||||
def nanos = Duration(n, NANOSECONDS)
|
||||
def nanosecond = Duration(n, NANOSECONDS)
|
||||
def nano = Duration(n, NANOSECONDS)
|
||||
|
||||
def microseconds = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def micros = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def microsecond = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def micro = Duration(n, TimeUnit.MICROSECONDS)
|
||||
def microseconds = Duration(n, MICROSECONDS)
|
||||
def micros = Duration(n, MICROSECONDS)
|
||||
def microsecond = Duration(n, MICROSECONDS)
|
||||
def micro = Duration(n, MICROSECONDS)
|
||||
|
||||
def milliseconds = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def millis = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def millisecond = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def milli = Duration(n, TimeUnit.MILLISECONDS)
|
||||
def milliseconds = Duration(n, MILLISECONDS)
|
||||
def millis = Duration(n, MILLISECONDS)
|
||||
def millisecond = Duration(n, MILLISECONDS)
|
||||
def milli = Duration(n, MILLISECONDS)
|
||||
|
||||
def seconds = Duration(n, TimeUnit.SECONDS)
|
||||
def second = Duration(n, TimeUnit.SECONDS)
|
||||
def seconds = Duration(n, SECONDS)
|
||||
def second = Duration(n, SECONDS)
|
||||
|
||||
def minutes = Duration(60 * n, TimeUnit.SECONDS)
|
||||
def minute = Duration(60 * n, TimeUnit.SECONDS)
|
||||
def minutes = Duration(60 * n, SECONDS)
|
||||
def minute = Duration(60 * n, SECONDS)
|
||||
|
||||
def hours = Duration(3600 * n, TimeUnit.SECONDS)
|
||||
def hour = Duration(3600 * n, TimeUnit.SECONDS)
|
||||
def hours = Duration(3600 * n, SECONDS)
|
||||
def hour = Duration(3600 * n, SECONDS)
|
||||
}
|
||||
|
||||
class DurationDouble(d: Double) {
|
||||
def nanoseconds = Duration(d, NANOSECONDS)
|
||||
def nanos = Duration(d, NANOSECONDS)
|
||||
def nanosecond = Duration(d, NANOSECONDS)
|
||||
def nano = Duration(d, NANOSECONDS)
|
||||
|
||||
def microseconds = Duration(d, MICROSECONDS)
|
||||
def micros = Duration(d, MICROSECONDS)
|
||||
def microsecond = Duration(d, MICROSECONDS)
|
||||
def micro = Duration(d, MICROSECONDS)
|
||||
|
||||
def milliseconds = Duration(d, MILLISECONDS)
|
||||
def millis = Duration(d, MILLISECONDS)
|
||||
def millisecond = Duration(d, MILLISECONDS)
|
||||
def milli = Duration(d, MILLISECONDS)
|
||||
|
||||
def seconds = Duration(d, SECONDS)
|
||||
def second = Duration(d, SECONDS)
|
||||
|
||||
def minutes = Duration(60 * d, SECONDS)
|
||||
def minute = Duration(60 * d, SECONDS)
|
||||
|
||||
def hours = Duration(3600 * d, SECONDS)
|
||||
def hour = Duration(3600 * d, SECONDS)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue