JS IR: Long
This commit is contained in:
@@ -14,7 +14,9 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform.builtIns
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -96,8 +98,10 @@ class JsIntrinsics(
|
||||
val jsNumberToDouble = getInternalFunction("numberToDouble")
|
||||
val jsNumberToInt = getInternalFunction("numberToInt")
|
||||
val jsNumberToShort = getInternalFunction("numberToShort")
|
||||
val jsNumberToLong = getInternalFunction("numberToLong")
|
||||
val jsToByte = getInternalFunction("toByte")
|
||||
val jsToShort = getInternalFunction("toShort")
|
||||
val jsToLong = getInternalFunction("toLong")
|
||||
|
||||
|
||||
// Other:
|
||||
@@ -112,6 +116,18 @@ class JsIntrinsics(
|
||||
val jsEquals = getInternalFunction("equals")
|
||||
|
||||
|
||||
val longConstructor =
|
||||
context.symbolTable.referenceConstructor(context.getClass(FqName("kotlin.Long")).constructors.single())
|
||||
val longToDouble = context.symbolTable.referenceSimpleFunction(
|
||||
context.getClass(FqName("kotlin.Long")).unsubstitutedMemberScope.findSingleFunction(
|
||||
Name.identifier("toDouble")
|
||||
)
|
||||
)
|
||||
val longToFloat = context.symbolTable.referenceSimpleFunction(
|
||||
context.getClass(FqName("kotlin.Long")).unsubstitutedMemberScope.findSingleFunction(
|
||||
Name.identifier("toFloat")
|
||||
)
|
||||
)
|
||||
|
||||
// Helpers:
|
||||
|
||||
|
||||
+118
-19
@@ -17,9 +17,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isFakeOverriddenFromAny
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
@@ -52,13 +50,6 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
for (type in primitiveNumbers) {
|
||||
op(type, OperatorNames.UNARY_PLUS, intrinsics.jsUnaryPlus)
|
||||
op(type, OperatorNames.UNARY_MINUS, intrinsics.jsUnaryMinus)
|
||||
|
||||
op(type, OperatorNames.ADD, intrinsics.jsPlus)
|
||||
op(type, OperatorNames.SUB, intrinsics.jsMinus)
|
||||
op(type, OperatorNames.MUL, intrinsics.jsMult)
|
||||
op(type, OperatorNames.DIV, intrinsics.jsDiv)
|
||||
op(type, OperatorNames.MOD, intrinsics.jsMod)
|
||||
op(type, OperatorNames.REM, intrinsics.jsMod)
|
||||
}
|
||||
|
||||
irBuiltIns.stringType.let {
|
||||
@@ -83,7 +74,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}
|
||||
|
||||
// Conversion rules are ported from NumberAndCharConversionFIF
|
||||
// TODO: Add Char, Long and Number conversions
|
||||
// TODO: Add Char and Number conversions
|
||||
|
||||
irBuiltIns.byteType.let {
|
||||
op(it, ConversionNames.TO_BYTE, intrinsics.jsAsIs)
|
||||
@@ -91,6 +82,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
op(it, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_INT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_SHORT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
for (type in listOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
|
||||
@@ -99,6 +91,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
op(type, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
|
||||
op(type, ConversionNames.TO_INT, intrinsics.jsNumberToInt)
|
||||
op(type, ConversionNames.TO_SHORT, intrinsics.jsNumberToShort)
|
||||
op(type, ConversionNames.TO_LONG, intrinsics.jsNumberToLong)
|
||||
}
|
||||
|
||||
irBuiltIns.intType.let {
|
||||
@@ -107,6 +100,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
op(it, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_INT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_SHORT, intrinsics.jsToShort)
|
||||
op(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
|
||||
irBuiltIns.shortType.let {
|
||||
@@ -115,13 +109,14 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
op(it, ConversionNames.TO_FLOAT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_INT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_SHORT, intrinsics.jsAsIs)
|
||||
op(it, ConversionNames.TO_LONG, intrinsics.jsToLong)
|
||||
}
|
||||
}
|
||||
|
||||
symbolToIrFunction.run {
|
||||
add(irBuiltIns.eqeqeqSymbol, intrinsics.jsEqeqeq)
|
||||
// TODO: implement it a right way
|
||||
add(irBuiltIns.eqeqSymbol, intrinsics.jsEqeq)
|
||||
add(irBuiltIns.eqeqSymbol, intrinsics.jsEquals.owner)
|
||||
// TODO: implement it a right way
|
||||
add(irBuiltIns.ieee754equalsFunByOperandType, intrinsics.jsEqeqeq)
|
||||
|
||||
@@ -147,24 +142,39 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (type in primitiveNumbers) {
|
||||
op(type, OperatorNames.ADD, withLongCoercion(intrinsics.jsPlus))
|
||||
op(type, OperatorNames.SUB, withLongCoercion(intrinsics.jsMinus))
|
||||
op(type, OperatorNames.MUL, withLongCoercion(intrinsics.jsMult))
|
||||
op(type, OperatorNames.DIV, withLongCoercion(intrinsics.jsDiv))
|
||||
op(type, OperatorNames.MOD, withLongCoercion(intrinsics.jsMod))
|
||||
op(type, OperatorNames.REM, withLongCoercion(intrinsics.jsMod))
|
||||
}
|
||||
}
|
||||
|
||||
nameToIrTransformer.run {
|
||||
addWithPredicate(
|
||||
Name.special(Namer.KCALLABLE_GET_NAME),
|
||||
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kCallableClass) } ?: false },
|
||||
{ call ->
|
||||
call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kCallableClass) } ?: false
|
||||
},
|
||||
{ call -> irCall(call, context.intrinsics.jsName.symbol, dispatchReceiverAsFirstArgument = true) })
|
||||
|
||||
addWithPredicate(
|
||||
Name.identifier(Namer.KPROPERTY_GET),
|
||||
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false },
|
||||
{ call -> irCall(call, context.intrinsics.jsPropertyGet.symbol, dispatchReceiverAsFirstArgument = true)}
|
||||
{ call ->
|
||||
call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false
|
||||
},
|
||||
{ call -> irCall(call, context.intrinsics.jsPropertyGet.symbol, dispatchReceiverAsFirstArgument = true) }
|
||||
)
|
||||
|
||||
addWithPredicate(
|
||||
Name.identifier(Namer.KPROPERTY_SET),
|
||||
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false},
|
||||
{ call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true)}
|
||||
{ call ->
|
||||
call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false
|
||||
},
|
||||
{ call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true) }
|
||||
)
|
||||
|
||||
addWithPredicate(
|
||||
@@ -189,12 +199,44 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transform(object : IrElementTransformerVoid() {
|
||||
|
||||
// TODO should this be a separate lowering?
|
||||
override fun <T> visitConst(expression: IrConst<T>): IrExpression {
|
||||
if (expression.kind is IrConstKind.Long) {
|
||||
val value = IrConstKind.Long.valueOf(expression)
|
||||
val high = (value shr 32).toInt()
|
||||
val low = value.toInt()
|
||||
return IrCallImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
context.intrinsics.longConstructor.owner.returnType,
|
||||
context.intrinsics.longConstructor
|
||||
).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildInt(context.irBuiltIns.intType, low))
|
||||
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, high))
|
||||
}
|
||||
}
|
||||
return super.visitConst(expression)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val call = super.visitCall(expression)
|
||||
|
||||
if (call is IrCall) {
|
||||
val symbol = call.symbol
|
||||
|
||||
// TODO create another map for this? Lower == to equals beforehand?
|
||||
if (symbol == irBuiltIns.eqeqSymbol) {
|
||||
val lhs = call.getValueArgument(0)!!
|
||||
val rhs = call.getValueArgument(1)!!
|
||||
|
||||
return when (translateEquals(lhs.type, rhs.type)) {
|
||||
is IdentityOperator -> irCall(call, intrinsics.jsEqeqeq.symbol)
|
||||
is EqualityOperator -> irCall(call, intrinsics.jsEqeq.symbol)
|
||||
else -> irCall(call, intrinsics.jsEquals)
|
||||
}
|
||||
}
|
||||
|
||||
symbolToIrFunction[symbol]?.let {
|
||||
return irCall(call, it.symbol)
|
||||
}
|
||||
@@ -229,6 +271,58 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun withLongCoercion(intrinsic: IrSimpleFunction): (IrCall) -> IrExpression = { call ->
|
||||
assert(call.valueArgumentsCount == 1)
|
||||
val arg = call.getValueArgument(0)!!
|
||||
val receiverType = call.dispatchReceiver!!.type
|
||||
|
||||
if (arg.type.isLong()) {
|
||||
when {
|
||||
// Double OP Long => Double OP Long.toDouble()
|
||||
receiverType.isDouble() -> {
|
||||
call.putValueArgument(0, IrCallImpl(
|
||||
call.startOffset,
|
||||
call.endOffset,
|
||||
context.intrinsics.longToDouble.owner.returnType,
|
||||
context.intrinsics.longToDouble
|
||||
).apply {
|
||||
dispatchReceiver = arg
|
||||
})
|
||||
}
|
||||
// Float OP Long => Float OP Long.toFloat()
|
||||
receiverType.isFloat() -> {
|
||||
call.putValueArgument(0, IrCallImpl(
|
||||
|
||||
call.startOffset,
|
||||
call.endOffset,
|
||||
context.intrinsics.longToFloat.owner.returnType,
|
||||
context.intrinsics.longToFloat
|
||||
).apply {
|
||||
dispatchReceiver = arg
|
||||
})
|
||||
}
|
||||
// {Byte, Short, Int} OP Long => {Byte, Sort, Int}.toLong() OP Long
|
||||
!receiverType.isLong() -> {
|
||||
call.dispatchReceiver = IrCallImpl(
|
||||
call.startOffset,
|
||||
call.endOffset,
|
||||
intrinsics.jsNumberToLong.owner.returnType,
|
||||
intrinsics.jsNumberToLong
|
||||
).apply {
|
||||
putValueArgument(0, call.dispatchReceiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (receiverType.isLong()) {
|
||||
// LHS is Long => use as is
|
||||
call
|
||||
} else {
|
||||
irCall(call, intrinsic.symbol, dispatchReceiverAsFirstArgument = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformEquals(call: IrCall): IrExpression {
|
||||
if (call.superQualifier != null) return call
|
||||
val symbol = call.symbol
|
||||
@@ -434,11 +528,16 @@ private fun <V> MutableMap<IrFunctionSymbol, V>.add(from: IrFunctionSymbol, to:
|
||||
put(from, to)
|
||||
}
|
||||
|
||||
private fun <K> MutableMap<K, (IrCall) -> IrExpression>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrExpression) {
|
||||
private fun <K> MutableMap<K, (IrCall) -> IrExpression>.addWithPredicate(
|
||||
from: K,
|
||||
predicate: (IrCall) -> Boolean,
|
||||
action: (IrCall) -> IrExpression
|
||||
) {
|
||||
put(from) { call: IrCall -> select({ predicate(call) }, { action(call) }, { call }) }
|
||||
}
|
||||
|
||||
private inline fun <T> select(crossinline predicate: () -> Boolean, crossinline ifTrue: () -> T, crossinline ifFalse: () -> T): T = if (predicate()) ifTrue() else ifFalse()
|
||||
private inline fun <T> select(crossinline predicate: () -> Boolean, crossinline ifTrue: () -> T, crossinline ifFalse: () -> T): T =
|
||||
if (predicate()) ifTrue() else ifFalse()
|
||||
|
||||
private class SimpleMemberKey(val klass: IrType, val name: Name) {
|
||||
// TODO drop custom equals and hashCode when IrTypes will have right equals
|
||||
|
||||
+2
-2
@@ -82,8 +82,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
is IrConstKind.Byte -> JsIntLiteral(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Short -> JsIntLiteral(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Int -> JsIntLiteral(kind.valueOf(expression))
|
||||
is IrConstKind.Long,
|
||||
is IrConstKind.Char -> super.visitConst(expression, context)
|
||||
is IrConstKind.Long -> throw IllegalStateException("Long const should have been lowered at this point")
|
||||
is IrConstKind.Char -> TODO("Char const")
|
||||
is IrConstKind.Float -> JsDoubleLiteral(kind.valueOf(expression).toDouble())
|
||||
is IrConstKind.Double -> JsDoubleLiteral(kind.valueOf(expression))
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ object OperatorNames {
|
||||
|
||||
val SHL = Name.identifier("shl")
|
||||
val SHR = Name.identifier("shr")
|
||||
val SHRU = Name.identifier("shru")
|
||||
val SHRU = Name.identifier("ushr")
|
||||
|
||||
val NOT = OperatorNameConventions.NOT
|
||||
|
||||
|
||||
@@ -46,13 +46,17 @@ abstract class BasicIrBoxTest(
|
||||
val runtime = listOf(
|
||||
"libraries/stdlib/js/src/kotlin/core.kt",
|
||||
"libraries/stdlib/js/irRuntime/core.kt",
|
||||
"libraries/stdlib/js/irRuntime/long.kt",
|
||||
"libraries/stdlib/js/irRuntime/longjs.kt",
|
||||
"libraries/stdlib/js/irRuntime/numberConversion.kt",
|
||||
"libraries/stdlib/js/irRuntime/compareTo.kt",
|
||||
"libraries/stdlib/js/irRuntime/annotations.kt",
|
||||
"libraries/stdlib/js/irRuntime/DefaultConstructorMarker.kt",
|
||||
"libraries/stdlib/js/irRuntime/exceptions.kt",
|
||||
"libraries/stdlib/js/irRuntime/internalAnnotations.kt",
|
||||
"libraries/stdlib/js/irRuntime/typeCheckUtils.kt"
|
||||
"libraries/stdlib/js/irRuntime/typeCheckUtils.kt",
|
||||
"core/builtins/native/kotlin/Number.kt",
|
||||
"core/builtins/native/kotlin/Comparable.kt"
|
||||
).map { createPsiFile(it) }
|
||||
|
||||
val filesToIgnore = listOf(
|
||||
|
||||
@@ -6,17 +6,16 @@
|
||||
package kotlin.js
|
||||
|
||||
fun equals(obj1: dynamic, obj2: dynamic): Boolean {
|
||||
if (obj1 == null) {
|
||||
return obj2 == null
|
||||
if (js("obj1 == null").unsafeCast<Boolean>()) {
|
||||
return js("obj2 == null").unsafeCast<Boolean>();
|
||||
}
|
||||
|
||||
if (obj2 == null) {
|
||||
return false
|
||||
if (js("obj2 == null").unsafeCast<Boolean>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return js("""
|
||||
if (typeof obj1 === "object" && typeof obj1.equals === "function") {
|
||||
return obj1.equals(obj2);
|
||||
if (typeof obj1 === "object" && typeof obj1.equals_Any_ === "function") {
|
||||
return obj1.equals_Any_(obj2);
|
||||
}
|
||||
|
||||
if (obj1 !== obj1) {
|
||||
@@ -31,7 +30,7 @@ fun equals(obj1: dynamic, obj2: dynamic): Boolean {
|
||||
}
|
||||
|
||||
fun toString(o: dynamic): String = when {
|
||||
o == null -> "null"
|
||||
js("o == null").unsafeCast<Boolean>() -> "null"
|
||||
isArrayish(o) -> "[...]"
|
||||
else -> js("o.toString()").unsafeCast<String>()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package kotlin
|
||||
|
||||
/**
|
||||
* Represents a 64-bit signed integer.
|
||||
*/
|
||||
public class Long internal constructor(
|
||||
internal val low: Int,
|
||||
internal val high: Int
|
||||
) : Number(), Comparable<Long> {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* A constant holding the minimum value an instance of Long can have.
|
||||
*/
|
||||
public const val MIN_VALUE: Long = -9223372036854775807L - 1L
|
||||
|
||||
/**
|
||||
* A constant holding the maximum value an instance of Long can have.
|
||||
*/
|
||||
public const val MAX_VALUE: Long = 9223372036854775807L
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public inline operator fun compareTo(other: Byte): Int = compareTo(other.toLong())
|
||||
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public inline operator fun compareTo(other: Short): Int = compareTo(other.toLong())
|
||||
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public inline operator fun compareTo(other: Int): Int = compareTo(other.toLong())
|
||||
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public override operator fun compareTo(other: Long): Int = compare(other)
|
||||
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public inline operator fun compareTo(other: Float): Int = toFloat().compareTo(other)
|
||||
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public inline operator fun compareTo(other: Double): Int = toDouble().compareTo(other)
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
public inline operator fun plus(other: Byte): Long = plus(other.toLong())
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
public inline operator fun plus(other: Short): Long = plus(other.toLong())
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
public inline operator fun plus(other: Int): Long = plus(other.toLong())
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
public operator fun plus(other: Long): Long = add(other)
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
public inline operator fun plus(other: Float): Float = toFloat() + other
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
public inline operator fun plus(other: Double): Double = toDouble() + other
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
public inline operator fun minus(other: Byte): Long = minus(other.toLong())
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
public inline operator fun minus(other: Short): Long = minus(other.toLong())
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
public inline operator fun minus(other: Int): Long = minus(other.toLong())
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
public operator fun minus(other: Long): Long = subtract(other)
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
public inline operator fun minus(other: Float): Float = toFloat() - other
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
public inline operator fun minus(other: Double): Double = toDouble() - other
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
public inline operator fun times(other: Byte): Long = times(other.toLong())
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
public inline operator fun times(other: Short): Long = times(other.toLong())
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
public inline operator fun times(other: Int): Long = times(other.toLong())
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
public operator fun times(other: Long): Long = multiply(other)
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
public inline operator fun times(other: Float): Float = toFloat() * other
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
public inline operator fun times(other: Double): Double = toDouble() * other
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
public inline operator fun div(other: Byte): Long = div(other.toLong())
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
public inline operator fun div(other: Short): Long = div(other.toLong())
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
public inline operator fun div(other: Int): Long = div(other.toLong())
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
public operator fun div(other: Long): Long = divide(other)
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
public inline operator fun div(other: Float): Float = toFloat() / other
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
public inline operator fun div(other: Double): Double = toDouble() / other
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
|
||||
public inline operator fun mod(other: Byte): Long = rem(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
|
||||
public inline operator fun mod(other: Short): Long = rem(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
|
||||
public inline operator fun mod(other: Int): Long = rem(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
|
||||
public inline operator fun mod(other: Long): Long = rem(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
|
||||
public inline operator fun mod(other: Float): Float = rem(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
|
||||
public inline operator fun mod(other: Double): Double = rem(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@SinceKotlin("1.1")
|
||||
public inline operator fun rem(other: Byte): Long = rem(other.toLong())
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@SinceKotlin("1.1")
|
||||
public inline operator fun rem(other: Short): Long = rem(other.toLong())
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@SinceKotlin("1.1")
|
||||
public inline operator fun rem(other: Int): Long = rem(other.toLong())
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@SinceKotlin("1.1")
|
||||
public operator fun rem(other: Long): Long = modulo(other)
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@SinceKotlin("1.1")
|
||||
public inline operator fun rem(other: Float): Float = toFloat() % other
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@SinceKotlin("1.1")
|
||||
public inline operator fun rem(other: Double): Double = toDouble() % other
|
||||
|
||||
/** Increments this value. */
|
||||
public operator fun inc(): Long = this + 1L
|
||||
|
||||
/** Decrements this value. */
|
||||
public operator fun dec(): Long = this - 1L
|
||||
|
||||
/** Returns this value. */
|
||||
public inline operator fun unaryPlus(): Long = this
|
||||
|
||||
/** Returns the negative of this value. */
|
||||
public operator fun unaryMinus(): Long = inv() + 1L
|
||||
|
||||
/* TODO
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Byte): LongRange
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Short): LongRange
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Int): LongRange
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Long): LongRange
|
||||
*/
|
||||
|
||||
/** Shifts this value left by the [bitCount] number of bits. */
|
||||
public infix fun shl(bitCount: Int): Long = shiftLeft(bitCount)
|
||||
|
||||
/** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with copies of the sign bit. */
|
||||
public infix fun shr(bitCount: Int): Long = shiftRight(bitCount)
|
||||
|
||||
/** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with zeros. */
|
||||
public infix fun ushr(bitCount: Int): Long = shiftRightUnsigned(bitCount)
|
||||
|
||||
/** Performs a bitwise AND operation between the two values. */
|
||||
public infix fun and(other: Long): Long = Long(low and other.low, high and other.high)
|
||||
|
||||
/** Performs a bitwise OR operation between the two values. */
|
||||
public infix fun or(other: Long): Long = Long(low or other.low, high or other.high)
|
||||
|
||||
/** Performs a bitwise XOR operation between the two values. */
|
||||
public infix fun xor(other: Long): Long = Long(low xor other.low, high xor other.high)
|
||||
|
||||
/** Inverts the bits in this value. */
|
||||
public fun inv(): Long = Long(low.inv(), high.inv())
|
||||
|
||||
public override fun toByte(): Byte = low.toByte()
|
||||
public override fun toChar(): Char = low.toChar()
|
||||
public override fun toShort(): Short = low.toShort()
|
||||
public override fun toInt(): Int = low
|
||||
public override fun toLong(): Long = this
|
||||
public override fun toFloat(): Float = toDouble().toFloat()
|
||||
public override fun toDouble(): Double = toNumber()
|
||||
|
||||
// TODO: is it still needed?
|
||||
private fun valueOf() = toDouble()
|
||||
|
||||
override fun equals(other: Any?): Boolean = other is Long && equalsLong(other)
|
||||
|
||||
override fun hashCode(): Int = hashCode(this)
|
||||
|
||||
override fun toString(): String = toString(10)
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* 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 (digits.length < 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 = high 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 approx = 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(approx) / Math.LN2)").unsafeCast<Int>()
|
||||
val delta = if (log2 <= 48) 1.0 else js("Math.pow(2, log2 - 48)").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(approx)
|
||||
var approxRem = approxRes.multiply(other)
|
||||
while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
|
||||
approx -= delta
|
||||
approxRes = fromNumber(approx)
|
||||
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)
|
||||
@@ -19,6 +19,10 @@ fun numberToShort(a: dynamic): Short = toShort(numberToInt(a))
|
||||
fun toByte(a: dynamic): Byte = js("a << 24 >> 24").unsafeCast<Byte>()
|
||||
fun toShort(a: dynamic): Short = js("a << 16 >> 16").unsafeCast<Short>()
|
||||
|
||||
fun numberToLong(a: dynamic): Long = fromNumber(a)
|
||||
|
||||
fun toLong(a: dynamic): Long = fromInt(a)
|
||||
|
||||
fun doubleToInt(a: dynamic) = js("""
|
||||
if (a > 2147483647) return 2147483647;
|
||||
if (a < -2147483648) return -2147483648;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
package kotlin.js
|
||||
|
||||
@kotlin.internal.DynamicExtension
|
||||
public fun <T> dynamic.unsafeCast(): T = this
|
||||
public inline fun <T> dynamic.unsafeCast(): T = this
|
||||
|
||||
private fun isInterfaceImpl(ctor: dynamic, iface: dynamic): Boolean {
|
||||
if (ctor === iface) return true;
|
||||
|
||||
Reference in New Issue
Block a user