revamp akka.util.Duration

- add comparison and arithmetic
- add infinite subtypes
This commit is contained in:
Roland Kuhn 2010-12-26 17:32:32 +01:00
parent 57d0e85a9a
commit c7150f6da3

View file

@ -7,8 +7,8 @@ package akka.util
import java.util.concurrent.TimeUnit
object Duration {
def apply(length: Long, unit: TimeUnit) = new Duration(length, unit)
def apply(length: Long, unit: String) = new Duration(length, timeUnit(unit))
def apply(length: Long, unit: TimeUnit) : Duration = new FiniteDuration(length, unit)
def apply(length: Long, unit: String) : Duration = new FiniteDuration(length, timeUnit(unit))
def timeUnit(unit: String) = unit.toLowerCase match {
case "nanoseconds" | "nanos" | "nanosecond" | "nano" => TimeUnit.NANOSECONDS
@ -16,6 +16,45 @@ object Duration {
case "milliseconds" | "millis" | "millisecond" | "milli" => TimeUnit.MILLISECONDS
case _ => TimeUnit.SECONDS
}
trait Infinite {
this : Duration =>
override def equals(other : Any) = false
def +(other : Duration) : Duration = this
def -(other : Duration) : Duration = this
def *(other : Double) : Duration = this
def /(other : Double) : Duration = this
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")
}
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
}
}
/**
@ -53,18 +92,177 @@ object Duration {
* val duration = 100.millis
* </pre>
*/
class Duration(val length: Long, val unit: TimeUnit) {
trait Duration {
def length : Long
def unit : TimeUnit
def toNanos : Long
def toMicros : Long
def toMillis : Long
def toSeconds : Long
def <(other : Duration) : Boolean
def <=(other : Duration) : Boolean
def >(other : Duration) : Boolean
def >=(other : Duration) : Boolean
def +(other : Duration) : Duration
def -(other : Duration) : Duration
def *(factor : Double) : Duration
def /(factor : Double) : Duration
def unary_- : Duration
def finite_? : Boolean
}
class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
def this(length: Long, unit: String) = this(length, Duration.timeUnit(unit))
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 + ")"
def <(other : Duration) = {
if (other.finite_?) {
toNanos < other.asInstanceOf[FiniteDuration].toNanos
} else {
other > this
}
}
def <=(other : Duration) = {
if (other.finite_?) {
toNanos <= other.asInstanceOf[FiniteDuration].toNanos
} else {
other >= this
}
}
def >(other : Duration) = {
if (other.finite_?) {
toNanos > other.asInstanceOf[FiniteDuration].toNanos
} else {
other < this
}
}
def >=(other : Duration) = {
if (other.finite_?) {
toNanos >= other.asInstanceOf[FiniteDuration].toNanos
} else {
other <= this
}
}
private def fromNanos(nanos : Long) : Duration = {
if (nanos % 1000000000L == 0) {
Duration(nanos / 1000000000L, TimeUnit.SECONDS)
} else if (nanos % 1000000L == 0) {
Duration(nanos / 1000000L, TimeUnit.MILLISECONDS)
} else if (nanos % 1000L == 0) {
Duration(nanos / 1000L, TimeUnit.MICROSECONDS)
} else {
Duration(nanos, TimeUnit.NANOSECONDS)
}
}
private def fromNanos(nanos : Double) : Duration = fromNanos(nanos.asInstanceOf[Long])
def +(other : Duration) = {
if (!other.finite_?) {
other
} else {
val nanos = toNanos + other.asInstanceOf[FiniteDuration].toNanos
fromNanos(nanos)
}
}
def -(other : Duration) = {
if (!other.finite_?) {
other
} else {
val nanos = toNanos - other.asInstanceOf[FiniteDuration].toNanos
fromNanos(nanos)
}
}
def *(factor : Double) = fromNanos(long2double(toNanos) * factor)
def /(factor : Double) = fromNanos(long2double(toNanos) / factor)
def unary_- = Duration(-length, unit)
def finite_? = true
override def equals(other : Any) =
other.isInstanceOf[FiniteDuration] &&
toNanos == other.asInstanceOf[FiniteDuration].toNanos
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 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)
implicit def intMult(i : Int) = new {
def *(d : Duration) = d * i
}
implicit def longMult(l : Long) = new {
def *(d : Duration) = d * l
}
}
class DurationInt(n: Int) {