/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
/**
* @file
*
* This file defines the functions related to 'Duration'.
*/
package std.core
const NS_PER_US: Int64 = 10 ** 3
const NS_PER_MS: Int64 = 10 ** 6
const NS_PER_SEC: Int64 = 10 ** 9
const MS_PER_SEC: Int64 = 10 ** 3
const US_PER_SEC: Int64 = 10 ** 6
const SECS_PER_MINUTE: Int64 = 60
const MAX_NANOSECOND: UInt32 = 999999999
const SECS_PER_HOUR: Int64 = 60 * 60
const SECS_PER_DAY: Int64 = 24 * 60 * 60
const MAX_INT64 = 0x7FFF_FFFF_FFFF_FFFF
const MIN_INT64 = -0x8000_0000_0000_0000
let MAX_NS_FLOAT64 = Float64(MAX_INT64) * Float64(NS_PER_SEC) + Float64(MAX_NANOSECOND)
let MIN_NS_FLOAT64 = Float64(MIN_INT64) * Float64(NS_PER_SEC)
const FLOAT64_0: Float64 = 0.0f64
const FLOAT64_1: Float64 = 1.0f64
const SECS_MAX: UInt64 = 0x8000_0000_0000_0000
const DUR_BASE: UInt32 = 0x3B9A_CA00 //10^9
/**
* Duration is used to represent a time interval with a minimum precision of nanoseconds.
* Duration can be expressed in the range of Duration.Min to Duration.Max.( [-2^63, 2^63-1) in seconds)
* Duration provides some common related methods, including static member instances of some common time intervals,
* calculation and comparison methods of time intervals, and the like.
*/
public struct Duration <: ToString & Hashable & Comparable<Duration> {
protected let sec: Int64
protected let ns: UInt32
protected const init(sec: Int64, ns: UInt32) {
this.sec = sec
this.ns = ns
}
static func of(sec: Int64, ns: Int64): Duration {
if (ns < 0) {
if (sec == Int64.Min) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
return Duration(sec - 1, UInt32(ns + NS_PER_SEC))
} else if (ns >= NS_PER_SEC) {
if (sec == Int64.Max) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
return Duration(sec + 1, UInt32(ns - NS_PER_SEC))
}
return Duration(sec, UInt32(ns))
}
/*
* Duration for 1 nanosecond.
*/
public static const nanosecond: Duration = Duration(0, 1)
/*
* Duration for 1 microsecond.
*/
public static const microsecond: Duration = Duration(0, 1000u32)
/*
* Duration for 1 millisecond.
*/
public static const millisecond: Duration = Duration(0, 1000000u32)
/*
* Duration for 1 second.
*/
public static const second: Duration = Duration(1, 0)
/*
* Duration for 1 minute.
*/
public static const minute: Duration = Duration(SECS_PER_MINUTE, 0)
/*
* Duration for 1 hour.
*/
public static const hour: Duration = Duration(SECS_PER_HOUR, 0)
/*
* Duration for 1 day.
*/
public static const day: Duration = Duration(SECS_PER_DAY, 0)
/*
* Duration for 0 nanosecond.
*/
public static const Zero: Duration = Duration(0, 0)
/*
* Duration for 2^63-1 seconds with 999,999,999 nanoseconds.
*/
public static const Max: Duration = Duration(MAX_INT64, MAX_NANOSECOND)
/*
* Duration for -2^63 seconds.
*/
public static const Min: Duration = Duration(MIN_INT64, 0)
/**
* Obtain the integer size of the current Duration instance in nanoseconds.
*
* @return Int64 - Integer size in nanoseconds, rounded up to the smaller absolute value.
*
* @throws ArithmeticException - if the duration in nanosecond exceeds the range of 'Int64'.
*/
public func toNanoseconds(): Int64 {
if (let Some(result) <- getResult(NS_PER_SEC)) {
return result
}
throw ArithmeticException("The duration in nanosecond exceeds the range of 'Int64'.")
}
/**
* Obtain the integer size of the current Duration instance in microseconds.
*
* @return Int64 - Integer size in microseconds, rounded up to the smaller absolute value.
*
* @throws ArithmeticException - if the duration in microsecond exceeds the range of 'Int64'.
*/
public func toMicroseconds(): Int64 {
if (let Some(result) <- getResult(US_PER_SEC)) {
return result
}
throw ArithmeticException("The duration in microsecond exceeds the range of 'Int64'.")
}
/**
* Obtain the integer size of the current Duration instance in milliseconds.
*
* @return Int64 - Integer size in milliseconds, rounded up to the smaller absolute value.
*
* @throws ArithmeticException - if the duration in millisecond exceeds the range of 'Int64'.
*/
public func toMilliseconds(): Int64 {
if (let Some(result) <- getResult(MS_PER_SEC)) {
return result
}
throw ArithmeticException("The duration in millisecond exceeds the range of 'Int64'.")
}
/**
* Obtain the integer size of the current Duration instance in seconds.
*
* @return Int64 - Integer size in seconds, rounded up to the smaller absolute value.
*/
public func toSeconds(): Int64 {
return getRealSecond()
}
/**
* Obtain the integer size of the current Duration instance in minutes.
*
* @return Int64 - Integer size in minutes, rounded up to the smaller absolute value.
*/
public func toMinutes(): Int64 {
return getRealSecond() / SECS_PER_MINUTE
}
/**
* Obtain the integer size of the current Duration instance in hours.
*
* @return Int64 - Integer size in hours, rounded up to the smaller absolute value.
*/
public func toHours(): Int64 {
return getRealSecond() / SECS_PER_HOUR
}
/**
* Obtain the integer size of the current Duration instance in days.
*
* @return Int64 - Integer size in days, rounded up to the smaller absolute value.
*/
public func toDays(): Int64 {
return getRealSecond() / SECS_PER_DAY
}
private func getRealSecond(): Int64 {
if (sec < 0 && ns > 0u32) {
return sec + 1
}
return sec
}
/**
* Obtain the string representation of the current Duration instance.
*
* @return String - The string representation of Duration
*
* The format is as follows: "1d2h3m4s5ms6us7ns".
* If the value of a unit is 0, this item is omitted.
* when the value of all units is 0, "0s" is returned.
*/
public func toString(): String {
return match {
case this == Zero => "0s"
case this == Min => "-106751991167300d15h30m8s"
case this == Max => "106751991167300d15h30m7s999ms999us999ns"
case _ =>
var (secs, nanos) = toSameSign()
let sb = if (secs < 0 || nanos < 0) {
(secs, nanos) = (-secs, -nanos)
StringBuilder(r'-')
} else {
StringBuilder()
}
let days = secs / SECS_PER_DAY
let hours = secs % SECS_PER_DAY / SECS_PER_HOUR
let minutes = secs % SECS_PER_HOUR / SECS_PER_MINUTE
let seconds = secs % SECS_PER_MINUTE
sb.append(days, "d").append(hours, "h").append(minutes, "m").append(seconds, "s")
let milliseconds = nanos / NS_PER_MS
let microseconds = nanos % NS_PER_MS / NS_PER_US
let nanoseconds = nanos % NS_PER_US
sb.append(milliseconds, "ms").append(microseconds, "us").append(nanoseconds, "ns")
return sb.toString()
}
}
/**
* Obtain the hash value of the current Duration instance.
*
* @return Int64 - Hash value of the current Duration instance.
*/
public func hashCode(): Int64 {
var dfh: DefaultHasher = DefaultHasher()
dfh.write(this.sec)
dfh.write(this.ns)
dfh.finish()
}
/**
* Obtain the duration instance for the absolute value of the interval of the current duration instance.
*
* @return Duration - The duration instance for the absolute value of the interval of the current instance.
*
* @throws ArithmeticException - If the absolute value is out of range for 'Duration'.
*/
public func abs(): Duration {
let (second, nanosecond) = toSameSign()
if (second == Int64.Min) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
if (second < 0 || nanosecond < 0) {
return Duration(-second, UInt32(-nanosecond))
}
return Duration(second, UInt32(nanosecond))
}
/**
* Add with another duration.
*
* @param other - Another duration.
* @return Duration - New duration instance after addition.
*
* @throws ArithmeticException - If the sum in nanoseconds is out of range for 'Duration'.
*
* @since 0.18.2
*/
public operator func +(other: Duration): Duration {
if ((other.sec | Int64(other.ns)) == 0) {
return this
}
if (isSumOverflow(this.sec, other.sec)) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
return Duration.of(this.sec + other.sec, Int64(this.ns) + Int64(other.ns))
}
/**
* Subtract another duration.
*
* @param other - Another duration.
* @return Duration - New duration instance after subtraction.
*
* @throws ArithmeticException - If the subtracted Value in nanoseconds is out of range for 'Duration'.
*
* @since 0.18.2
*/
public operator func -(other: Duration): Duration {
if ((other.sec | Int64(other.ns)) == 0) {
return this
}
if (checkSub(this.sec, other.sec)) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
return Duration.of(this.sec - other.sec, Int64(this.ns) - Int64(other.ns))
}
/**
* Multiply by the specified 'Int64' value.
*
* @param multiplier - The specified 'Int64' value to multiply.
* @return Duration - New duration instance after multiplication.
*
* @throws ArithmeticException If the multiplied value in nanoseconds is out of range for 'Duration'.
*
* @since 0.18.2
*/
public operator func *(multiplier: Int64): Duration {
if (this == Zero || multiplier == 0) {
return Zero
} else if (multiplier == -1 && this != Min) {
let (secs, nanos) = toSameSign()
return Duration.of(-secs, -nanos)
} else if (multiplier == 1) {
return this
} else if (this == Min || this == Max) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
let (secU64, nsU32, multi, sign) = toUnsignedNum(multiplier)
if (let Some(v) <- durMul(secU64, nsU32, multi, sign)) {
return v
}
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
/**
* Multiply by the specified 'Float64' value.
*
* @param multiplier - The specified 'Float64' value to multiply.
* @return Duration - New duration instance after multiplication.
*
* @throws IllegalArgumentException - If the value of @p multiplier is NaN(not a number).
* @throws ArithmeticException - If the multiplied value in nanoseconds is out of range for 'Duration'.
*
* @since 0.18.2
*/
public operator func *(multiplier: Float64): Duration {
if (this == Zero || multiplier == FLOAT64_0) {
return Zero
} else if (multiplier == FLOAT64_1) {
return this
} else if (multiplier != multiplier) {
throw IllegalArgumentException("The value of operand cannot be Float64.NaN(not a number)!")
}
let result = this.toFloat64Nanoseconds() * multiplier
return getDurationByFloat64(result).getOrThrow(
{=> ArithmeticException("Out of range of representation of 'Duration'!")})
}
func toFloat64Nanoseconds(): Float64 {
return Float64(sec) * Float64(NS_PER_SEC) + Float64(ns)
}
private func getDurationByFloat64(ns_f64: Float64): Option<Duration> {
return if (ns_f64 < MAX_NS_FLOAT64 && ns_f64 > MIN_NS_FLOAT64) {
let second = Int64(ns_f64 / Float64(NS_PER_SEC))
let nanos: Int64 = Int64(ns_f64 - Float64(second) * Float64(NS_PER_SEC))
Duration.of(second, nanos)
} else if (ns_f64 == MAX_NS_FLOAT64) {
Duration.Max
} else if (ns_f64 == MIN_NS_FLOAT64) {
Duration.Min
} else {
None
}
}
/**
* Divide by the specified 'Int64' value.
*
* @param divisor - the specified 'Int64' value.
* @return Duration - New instance after division.
*
* @throws IllegalArgumentException - If the value of @p divisor is 0.
* @throws ArithmeticException - If the divided value in nanoseconds is out of range for 'Duration'.
*/
public operator func /(divisor: Int64): Duration {
if (divisor == 0) {
throw IllegalArgumentException("The value of right operand cannot be 0!")
} else if (divisor == 1) {
return this
}
if (this == Min && divisor == -1) {
throw ArithmeticException("Out of range of representation of 'Duration'!")
}
let (secU64, nsU32, denominator, sign) = toUnsignedNum(divisor)
if (denominator <= 0xFFFF_FFFF) {
let nanos = UInt64(nsU32)
let (seconds, extraSec) = (secU64 / denominator, secU64 % denominator)
var nanoseconds = nanos / denominator
let extraNs = nanos % denominator
nanoseconds += ((extraSec * UInt64(NS_PER_SEC) + extraNs) / denominator)
if (sign) {
return Duration.of(Int64(seconds), Int64(nanoseconds))
}
return Duration.of(-Int64(seconds), -Int64(nanoseconds))
}
let (seconds, nanoseconds) = durDiv(secU64, nsU32, denominator)
if (sign) {
return Duration(seconds, UInt32(nanoseconds))
}
return Duration.of(-seconds, -nanoseconds)
}
/**
* Divide by the specified 'Float64' value.
*
* @param divisor - the specified 'Float64' value.
* @return Duration - New instance after division.
*
* @throws IllegalArgumentException - If the value of @p divisor is 0 or NaN(not a number).
* @throws ArithmeticException - If the divided value in nanoseconds is out of the range for 'Duration'.
*/
public operator func /(divisor: Float64): Duration {
if (this == Zero) {
return Zero
}
if (divisor == FLOAT64_0) {
throw IllegalArgumentException("The value of right operand cannot be 0.0!")
} else if (divisor == FLOAT64_1) {
return this
} else if (divisor != divisor) {
throw IllegalArgumentException("The value of right operand cannot be Float64.NaN(not a number)!")
}
let result = this.toFloat64Nanoseconds() / divisor
return getDurationByFloat64(result).getOrThrow(
{=> ArithmeticException("Out of range of representation of 'Duration'!")})
}
/**
* Divide by another duration.
*
* @param other - Another duration.
* @return Float64 - The divided 'Float64' value.
*
* @throws IllegalArgumentException - If @p other is Duration.Zero.
*/
public operator func /(other: Duration): Float64 {
if (other == Zero) {
throw IllegalArgumentException("The value of right operand cannot be Duration.Zero!")
}
return this.toFloat64Nanoseconds() / other.toFloat64Nanoseconds()
}
/**
* Report whether it is equal to another Duration.
*
* @param other another duration.
* @return true if equal @p other, otherwise false.
*
* @since 0.18.2
*/
public operator func ==(other: Duration): Bool {
return this.sec == other.sec && this.ns == other.ns
}
/**
* Report whether it is not equal to another Duration.
*
* @param other another duration.
* @return true if not equal @p other, otherwise false.
*
* @since 0.18.2
*/
public operator func !=(other: Duration): Bool {
return !(this == other)
}
/**
* Report whether it is greater than or equal to another Duration.
*
* @param other another duration.
* @return true if greater than or equal to @p other, otherwise false.
*
* @since 0.18.2
*/
public operator func >=(other: Duration): Bool {
return if (this.sec == other.sec) {
this.ns >= other.ns
} else if (this.sec < other.sec) {
false
} else {
true
}
}
/**
* Report whether it is greater than another Duration.
*
* @param other another duration.
* @return true if greater than @p other, otherwise false.
*
* @since 0.18.2
*/
public operator func >(other: Duration): Bool {
return if (this.sec == other.sec) {
this.ns > other.ns
} else if (this.sec < other.sec) {
false
} else {
true
}
}
/**
* Report whether it is less than or equal to another Duration.
*
* @param other another duration.
* @return true if less than or equal to @p other, otherwise false.
*
* @since 0.18.2
*/
public operator func <=(other: Duration): Bool {
return !(this > other)
}
/**
* Report whether it is less than another Duration.
*
* @param other another duration.
* @return true if less than @p other, otherwise false.
*
* @since 0.18.2
*/
public operator func <(other: Duration): Bool {
return !(this >= other)
}
/**
* Compare the relationship between the current duration instance and another duration instance.
*
* @param other - Another duration instance for comparison
* @return Ordering - Indicating the relationship between two duration instances.
*/
public func compare(other: Duration): Ordering {
return match {
case this < other => Ordering.LT
case this > other => Ordering.GT
case _ => Ordering.EQ
}
}
@OverflowWrapping
func toUnsignedNum(r: Int64): (UInt64, UInt32, UInt64, Bool) {
var sign = r > 0
let (secs, nanos) = toSameSign()
let rOperand = if (sign) {
UInt64(r)
} else {
UInt64(-r)
}
if (this > Zero) {
return (UInt64(secs), UInt32(nanos), rOperand, sign)
} else {
return (UInt64(-secs), UInt32(-nanos), rOperand, !sign)
}
}
private func getResult(div: Int64): ?Int64 {
let (second, nanosecond) = toSameSign()
if (second > 0 && second > (Int64.Max - nanosecond) / div) {
return None
} else if (second < 0 && second < (Int64.Min - nanosecond) / div) {
return None
}
return second * div + nanosecond * div / NS_PER_SEC
}
private func toSameSign(): (Int64, Int64) {
var second = this.sec
var nanosecond = Int64(this.ns)
if (second < 0 && nanosecond > 0) {
second += 1
nanosecond -= NS_PER_SEC
}
return (second, nanosecond)
}
}
func durMul(secs: UInt64, nanos: UInt32, multiplier: UInt64, sign: Bool): ?Duration {
let (count, nanoseconds) = u32MulU64(nanos, multiplier)
var seconds: UInt64
if (secs == 0u64) {
seconds = count
} else {
match (tryU64Mul(secs, multiplier)) {
case Some(v) => seconds = v
case None => return None
}
match (tryU64Add(seconds, count)) {
case Some(v) => seconds = v
case None => return None
}
// sign: +, second < SECS_MAX
// sign: -, second = SECS_MAX, nanoseconds = 0 || second <= SECS_MAX
// seconds is not over than SECS_MAX
if (seconds == SECS_MAX) {
if (!sign && nanoseconds == 0) {
return Duration.Min
}
return None
}
}
if (sign) {
return Duration(Int64(seconds), nanoseconds)
}
return Duration.of(-Int64(seconds), -Int64(nanoseconds))
}
func u32MulU64(thisInt: UInt32, thatInt: UInt64): (UInt64, UInt32) {
let thatLow32: UInt32 = thatInt % DUR_BASE
let thatHigh32: UInt64 = thatInt / UInt64(NS_PER_SEC)
let res: UInt64 = UInt64(thisInt) * UInt64(thatLow32)
let second: UInt64 = thisInt * thatHigh32 + (res / UInt64(NS_PER_SEC))
let nanosecond: UInt32 = res % DUR_BASE
return (second, nanosecond)
}
func tryU64Mul(left: UInt64, right: UInt64): ?UInt64 {
if (left == 0u64) {
return 0u64
}
if (right > SECS_MAX / left) {
return None
}
return left * right
}
func tryU64Add(left: UInt64, right: UInt64): ?UInt64 {
if (right > SECS_MAX - left) {
return None
}
return left + right
}
// return true if overflow
func checkSub(left: Int64, right: Int64): Bool {
return (right > 0 && left <= Int64.Min + right) || (right < 0 && left >= Int64.Max + right)
}
func toSecNsBase(num: UInt64): (UInt32, UInt32, UInt32) {
let res0 = num % DUR_BASE
let res1 = num / DUR_BASE % DUR_BASE
let res2 = num / DUR_BASE / DUR_BASE
return (UInt32(res2), res1, res0)
}
func durDiv(secs: UInt64, nanos: UInt32, divisor: UInt64): (Int64, Int64) {
let (divisor2, divisor1, divisor0) = toSecNsBase(divisor)
let (sec2, sec1, sec0) = toSecNsBase(secs)
if (divisor2 == 0) {
let times = DUR_BASE / (divisor1 + 1)
var (ds1, ds0) = (divisor1, divisor0)
let (dd4, dd3, dd2, dd1, dd0) = if (times == 1) {
(UInt32(0), sec2, sec1, sec0, nanos)
} else {
(_, ds1, ds0) = u32TwoMul(divisor1, divisor0, times)
u32DividendMul(sec2, sec1, sec0, nanos, times)
}
let dividend2 = UInt64(dd4) * DUR_BASE + UInt64(dd3)
let res2 = divAndMod(dividend2, dd2, ds1, ds0)
var (p2, p1, p0) = u32TwoMul(ds1, ds0, res2)
var (c2, c1, c0) = (Int64(dd4) - Int64(p2), Int64(dd3) - Int64(p1), Int64(dd2) - Int64(p0))
var (_, d1, d0) = getDifference(c2, c1, c0)
let dividend1 = UInt64(d1) * DUR_BASE + UInt64(d0)
let res1 = divAndMod(dividend1, dd1, ds1, ds0)
(p2, p1, p0) = u32TwoMul(ds1, ds0, res1)
(c2, c1, c0) = (Int64(d1) - Int64(p2), Int64(d0) - Int64(p1), Int64(dd1) - Int64(p0))
(_, d1, d0) = getDifference(c2, c1, c0)
let dividend0 = UInt64(d1) * DUR_BASE + UInt64(d0)
let res0 = divAndMod(dividend0, dd0, ds1, ds0)
return (Int64(res2) * NS_PER_SEC + Int64(res1), Int64(res0))
} else {
let times = DUR_BASE / UInt32(divisor2 + 1)
let (dd4, dd3, dd2, dd1, dd0) = u32DividendMul(sec2, sec1, sec0, nanos, times)
let (_, ds2, ds1, ds0) = u32ThreeMul(divisor2, divisor1, divisor0, times)
let dividend2 = UInt64(dd4) * DUR_BASE + UInt64(dd3)
var res1 = divAndMod(dividend2, dd2, ds2, ds1)
var (p3, p2, p1, p0) = u32ThreeMul(ds2, ds1, ds0, res1)
var (c3, c2, c1, c0) = (Int64(dd4) - Int64(p3), Int64(dd3) - Int64(p2), Int64(dd2) - Int64(p1), Int64(dd1) -
Int64(p0))
var (d3, d2, d1, d0) = getDifference(c3, c2, c1, c0)
if (d3 < 0) {
res1--
(p3, p2, p1, p0) = u32ThreeMul(ds2, ds1, ds0, res1)
(c3, c2, c1, c0) = (Int64(dd4) - Int64(p3), Int64(dd3) - Int64(p2), Int64(dd2) - Int64(p1), Int64(dd1) -
Int64(p0))
(d3, d2, d1, d0) = getDifference(c3, c2, c1, c0)
}
let dividend1 = UInt64(d2) * DUR_BASE + UInt64(d1)
var res0 = divAndMod(dividend1, UInt32(d0), ds2, ds1)
(p3, p2, p1, p0) = u32ThreeMul(ds2, ds1, ds0, res0)
(c3, c2, c1, c0) = (Int64(d2) - Int64(p3), Int64(d1) - Int64(p2), Int64(d0) - Int64(p1), Int64(dd0) - Int64(p0))
(d3, d2, d1, d0) = getDifference(c3, c2, c1, c0)
if (d3 < 0) {
res0--
}
return (Int64(res1), Int64(res0))
}
}
func getDifference(num3: Int64, num2: Int64, num1: Int64, num0: Int64): (Int64, Int64, Int64, Int64) {
var (res3, res2, res1, res0) = (num3, num2, num1, num0)
if (res0 < 0) {
res1--
res0 += NS_PER_SEC
}
if (res1 < 0) {
res2--
res1 += NS_PER_SEC
}
if (res2 < 0) {
res3--
res2 += NS_PER_SEC
}
return (res3, res2, res1, res0)
}
func getDifference(num2: Int64, num1: Int64, num0: Int64): (UInt32, UInt32, UInt32) {
var (res2, res1, res0) = (num2, num1, num0)
if (res0 < 0) {
res1--
res0 += NS_PER_SEC
}
if (res1 < 0) {
res2--
res1 += NS_PER_SEC
}
return (UInt32(res2), UInt32(res1), UInt32(res0))
}
func u32TwoMul(num1: UInt32, num0: UInt32, multiplier: UInt32): (UInt32, UInt32, UInt32) {
var res0: UInt64 = UInt64(num0) * UInt64(multiplier)
var res1: UInt64 = UInt64(num1) * UInt64(multiplier) + res0 / DUR_BASE
var res2: UInt64 = res1 / DUR_BASE
return (UInt32(res2), res1 % DUR_BASE, res0 % DUR_BASE)
}
func u32ThreeMul(num2: UInt32, num1: UInt32, num0: UInt32, multiplier: UInt32): (UInt32, UInt32, UInt32, UInt32) {
var res0: UInt64 = UInt64(num0) * UInt64(multiplier)
var res1: UInt64 = UInt64(num1) * UInt64(multiplier) + res0 / DUR_BASE
var res2: UInt64 = UInt64(num2) * UInt64(multiplier) + res1 / DUR_BASE
var res3: UInt64 = res2 / DUR_BASE
return (UInt32(res3), res2 % DUR_BASE, res1 % DUR_BASE, res0 % DUR_BASE)
}
func u32DividendMul(num3: UInt32, num2: UInt32, num1: UInt32, num0: UInt32, times: UInt32): (UInt32, UInt32, UInt32,
UInt32, UInt32) {
// the place is 10^9
var res0: UInt64 = UInt64(num0) * UInt64(times)
var res1: UInt64 = UInt64(num1) * UInt64(times) + res0 / DUR_BASE
var res2: UInt64 = UInt64(num2) * UInt64(times) + res1 / DUR_BASE
var res3: UInt64 = UInt64(num3) * UInt64(times) + res2 / DUR_BASE
var res4: UInt64 = res3 / DUR_BASE
return (UInt32(res4), res3 % DUR_BASE, res2 % DUR_BASE, res1 % DUR_BASE, res0 % DUR_BASE)
}
func divAndMod(dividend: UInt64, dividend2: UInt32, divisor2: UInt32, divisor1: UInt32): (UInt32) {
var discuss = dividend / divisor2
var remainder = dividend % divisor2
if (discuss != UInt64(DUR_BASE) && discuss * divisor1 <= UInt64(remainder) * UInt64(DUR_BASE) + UInt64(dividend2)) {
return (UInt32(discuss))
}
while (remainder < DUR_BASE) {
if (discuss == UInt64(DUR_BASE) || discuss * divisor1 > UInt64(remainder) * UInt64(DUR_BASE) + UInt64(dividend2)) {
discuss--
remainder += divisor2
}
}
return (UInt32(discuss))
}
extend Int64 {
/**
* Multiply by a duration Instance.
*
* @param r - a duration Instance.
* @return Duration - New duration instance after multiplication.
*
* @throws ArithmeticException - If the multiplied value in nanoseconds is out of range for 'Duration'.
*/
public operator func *(r: Duration): Duration {
return r * this
}
}
extend Int64 {
operator func -(r: UInt32): Int64 {
return this - Int64(r)
}
}
extend UInt64 {
operator func *(r: UInt32): UInt64 {
return this * UInt64(r)
}
operator func /(r: UInt32): UInt64 {
return this / UInt64(r)
}
operator func %(r: UInt32): UInt32 {
return UInt32(this % UInt64(r))
}
}
extend UInt32 {
operator func *(r: UInt64): UInt64 {
return UInt64(r) * this
}
}
extend Float64 {
/**
* Multiplies this floating-point factor by a Duration instance.
*
* @param r - the duration to scale.
* @return Duration - New duration instance after floating-point multiplication.
*
* @throws ArithmeticException - If the multiplied value in nanoseconds is out of range for 'Duration'.
*/
public operator func *(r: Duration): Duration {
return r * this
}
}
extend StringBuilder {
func append(num: Int64, unit: String): StringBuilder {
if (num != 0) {
this.append(num)
this.append(unit)
}
return this
}
}
func isSumOverflow(left: Int64, right: Int64): Bool {
return (right > 0 && left > MAX_INT64 - right) || (right < 0 && left < MIN_INT64 - right)
}