1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
|
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
package kotlin
internal fun Long.toNumber() = high * TWO_PWR_32_DBL_ + getLowBitsUnsigned()
internal fun Long.getLowBitsUnsigned() = if (low >= 0) low.toDouble() else TWO_PWR_32_DBL_ + low
internal fun hashCode(l: Long) = l.low xor l.high
internal fun Long.toString(radix: Int): String {
if (radix < 2 || 36 < radix) {
throw Exception("radix out of range: $radix")
}
if (isZero()) {
return "0"
}
if (isNegative()) {
if (equalsLong(MIN_VALUE)) {
// We need to change the Long value before it can be negated, so we remove
// the bottom-most digit in this base and then recurse to do the rest.
val radixLong = fromInt(radix)
val div = div(radixLong)
val rem = div.multiply(radixLong).subtract(this).toInt();
return js("div.toString(radix) + rem.toString(radix)")
} else {
return "-${negate().toString()}"
}
}
// Do several (6) digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
val radixToPower = fromNumber(js("Math.pow(radix, 6)").unsafeCast<Double>())
var rem = this
var result = ""
while (true) {
val remDiv = rem.div(radixToPower)
val intval = rem.subtract(remDiv.multiply(radixToPower)).toInt()
var digits = js("intval.toString(radix)").unsafeCast<String>()
rem = remDiv
if (rem.isZero()) {
return digits + result
} else {
while (js("digits.length").unsafeCast<Int>() < 6) {
digits = "0" + digits
}
result = digits + result
}
}
}
internal fun Long.negate() = unaryMinus()
internal fun Long.isZero() = high == 0 && low == 0
internal fun Long.isNegative() = high < 0
internal fun Long.isOdd() = low and 1 == 1
internal fun Long.equalsLong(other: Long) = high == other.high && low == other.low
internal fun Long.lessThan(other: Long) = compare(other) < 0
internal fun Long.lessThanOrEqual(other: Long) = compare(other) <= 0
internal fun Long.greaterThan(other: Long) = compare(other) > 0
internal fun Long.greaterThanOrEqual(other: Long) = compare(other) >= 0
internal fun Long.compare(other: Long): Int {
if (equalsLong(other)) {
return 0;
}
val thisNeg = isNegative();
val otherNeg = other.isNegative();
return when {
thisNeg && !otherNeg -> -1
!thisNeg && otherNeg -> 1
// at this point, the signs are the same, so subtraction will not overflow
subtract(other).isNegative() -> -1
else -> 1
}
}
internal fun Long.add(other: Long): Long {
// Divide each number into 4 chunks of 16 bits, and then sum the chunks.
val a48 = high ushr 16
val a32 = high and 0xFFFF
val a16 = low ushr 16
val a00 = low and 0xFFFF
val b48 = other.high ushr 16
val b32 = other.high and 0xFFFF
val b16 = other.low ushr 16
val b00 = other.low and 0xFFFF
var c48 = 0
var c32 = 0
var c16 = 0
var c00 = 0
c00 += a00 + b00
c16 += c00 ushr 16
c00 = c00 and 0xFFFF
c16 += a16 + b16
c32 += c16 ushr 16
c16 = c16 and 0xFFFF
c32 += a32 + b32
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c48 += a48 + b48
c48 = c48 and 0xFFFF
return Long((c16 shl 16) or c00, (c48 shl 16) or c32)
}
internal fun Long.subtract(other: Long) = add(other.unaryMinus())
internal fun Long.multiply(other: Long): Long {
if (isZero()) {
return ZERO
} else if (other.isZero()) {
return ZERO
}
if (equalsLong(MIN_VALUE)) {
return if (other.isOdd()) MIN_VALUE else ZERO
} else if (other.equalsLong(MIN_VALUE)) {
return if (isOdd()) MIN_VALUE else ZERO
}
if (isNegative()) {
return if (other.isNegative()) {
negate().multiply(other.negate())
} else {
negate().multiply(other).negate()
}
} else if (other.isNegative()) {
return multiply(other.negate()).negate()
}
// If both longs are small, use float multiplication
if (lessThan(TWO_PWR_24_) && other.lessThan(TWO_PWR_24_)) {
return fromNumber(toNumber() * other.toNumber())
}
// Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
// We can skip products that would overflow.
val a48 = high ushr 16
val a32 = high and 0xFFFF
val a16 = low ushr 16
val a00 = low and 0xFFFF
val b48 = other.high ushr 16
val b32 = other.high and 0xFFFF
val b16 = other.low ushr 16
val b00 = other.low and 0xFFFF
var c48 = 0
var c32 = 0
var c16 = 0
var c00 = 0
c00 += a00 * b00
c16 += c00 ushr 16
c00 = c00 and 0xFFFF
c16 += a16 * b00
c32 += c16 ushr 16
c16 = c16 and 0xFFFF
c16 += a00 * b16
c32 += c16 ushr 16
c16 = c16 and 0xFFFF
c32 += a32 * b00
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c32 += a16 * b16
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c32 += a00 * b32
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48
c48 = c48 and 0xFFFF
return Long(c16 shl 16 or c00, c48 shl 16 or c32)
}
internal fun Long.divide(other: Long): Long {
if (other.isZero()) {
throw Exception("division by zero")
} else if (isZero()) {
return ZERO
}
if (equalsLong(MIN_VALUE)) {
if (other.equalsLong(ONE) || other.equalsLong(NEG_ONE)) {
return MIN_VALUE // recall that -MIN_VALUE == MIN_VALUE
} else if (other.equalsLong(MIN_VALUE)) {
return ONE
} else {
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
val halfThis = shiftRight(1)
val approx = halfThis.div(other).shiftLeft(1)
if (approx.equalsLong(ZERO)) {
return if (other.isNegative()) ONE else NEG_ONE
} else {
val rem = subtract(other.multiply(approx))
return approx.add(rem.div(other))
}
}
} else if (other.equalsLong(MIN_VALUE)) {
return ZERO
}
if (isNegative()) {
return if (other.isNegative()) {
negate().div(other.negate())
} else {
negate().div(other).negate()
}
} else if (other.isNegative()) {
return div(other.negate()).negate()
}
// Repeat the following until the remainder is less than other: find a
// floating-point that approximates remainder / other *from below*, add this
// into the result, and subtract it from the remainder. It is critical that
// the approximate value is less than or equal to the real value so that the
// remainder never becomes negative.
var res = ZERO
var rem = this
while (rem.greaterThanOrEqual(other)) {
// Approximate the result of division. This may be a little greater or
// smaller than the actual value.
val approxDouble = rem.toNumber() / other.toNumber()
var approx2 = js("Math.max(1, Math.floor(approxDouble))").unsafeCast<Double>()
// We will tweak the approximate result by changing it in the 48-th digit or
// the smallest non-fractional digit, whichever is larger.
val log2 = js("Math.ceil(Math.log(approx2) / Math.LN2)").unsafeCast<Int>()
// TODO: log2 is renamed but usage in js() functions is not
val log2_minus48 = log2 - 48
val delta = if (log2 <= 48) 1.0 else js("Math.pow(2, log2_minus48)").unsafeCast<Double>()
// Decrease the approximation until it is smaller than the remainder. Note
// that if it is too large, the product overflows and is negative.
var approxRes = fromNumber(approx2)
var approxRem = approxRes.multiply(other)
while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
approx2 -= delta
approxRes = fromNumber(approx2)
approxRem = approxRes.multiply(other)
}
// We know the answer can't be zero... and actually, zero would cause
// infinite recursion since we would make no progress.
if (approxRes.isZero()) {
approxRes = ONE
}
res = res.add(approxRes)
rem = rem.subtract(approxRem)
}
return res
}
internal fun Long.modulo(other: Long) = subtract(div(other).multiply(other))
internal fun Long.shiftLeft(numBits: Int): Long {
val numBits = numBits and 63
if (numBits == 0) {
return this
} else {
if (numBits < 32) {
return Long(low shl numBits, (high shl numBits) or (low ushr (32 - numBits)))
} else {
return Long(0, low shl (numBits - 32))
}
}
}
internal fun Long.shiftRight(numBits: Int): Long {
val numBits = numBits and 63
if (numBits == 0) {
return this
} else {
if (numBits < 32) {
return Long((low ushr numBits) or (high shl (32 - numBits)), high shr numBits)
} else {
return Long(high shr (numBits - 32), if (high >= 0) 0 else -1)
}
}
}
internal fun Long.shiftRightUnsigned(numBits: Int): Long {
val numBits = numBits and 63
if (numBits == 0) {
return this
} else {
if (numBits < 32) {
return Long((low ushr numBits) or (high shl (32 - numBits)), high ushr numBits)
} else return if (numBits == 32) {
Long(high, 0)
} else {
Long(high ushr (numBits - 32), 0)
}
}
}
/**
* Returns a Long representing the given (32-bit) integer value.
* @param {number} value The 32-bit integer in question.
* @return {!Kotlin.Long} The corresponding Long value.
*/
// TODO: cache
internal fun fromInt(value: Int) = Long(value, if (value < 0) -1 else 0)
/**
* Returns a Long representing the given value, provided that it is a finite
* number. Otherwise, zero is returned.
* @param {number} value The number in question.
* @return {!Kotlin.Long} The corresponding Long value.
*/
internal fun fromNumber(value: Double): Long {
if (js("isNaN(value)").unsafeCast<Boolean>() || !js("isFinite(value)").unsafeCast<Boolean>()) {
return ZERO;
} else if (value <= -TWO_PWR_63_DBL_) {
return MIN_VALUE;
} else if (value + 1 >= TWO_PWR_63_DBL_) {
return MAX_VALUE;
} else if (value < 0) {
return fromNumber(-value).negate();
} else {
val twoPwr32 = TWO_PWR_32_DBL_
return Long(
js("(value % twoPwr32) | 0").unsafeCast<Int>(),
js("(value / twoPwr32) | 0").unsafeCast<Int>()
)
}
}
private val TWO_PWR_16_DBL_ = (1 shl 16).toDouble()
private val TWO_PWR_24_DBL_ = (1 shl 24).toDouble()
private val TWO_PWR_32_DBL_ = TWO_PWR_16_DBL_ * TWO_PWR_16_DBL_
private val TWO_PWR_64_DBL_ = TWO_PWR_32_DBL_ * TWO_PWR_32_DBL_
private val TWO_PWR_63_DBL_ = TWO_PWR_64_DBL_ / 2
private val ZERO = fromInt(0)
private val ONE = fromInt(1)
private val NEG_ONE = fromInt(-1)
private val MAX_VALUE = Long(-1, -1 ushr 1)
private val MIN_VALUE = Long(0, 1 shl 31)
private val TWO_PWR_24_ = fromInt(1 shl 24)
|