WASM: Implement integer to string conversion operations
This commit is contained in:
committed by
TeamCityServer
parent
2538caa84f
commit
f34a079699
@@ -93,7 +93,7 @@ public class Char private constructor(public val value: Char) : Comparable<Char>
|
|||||||
this.toInt().toDouble()
|
this.toInt().toDouble()
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
charToString(this)
|
String(charArrayOf(this))
|
||||||
|
|
||||||
override fun hashCode(): Int =
|
override fun hashCode(): Int =
|
||||||
this.toInt().hashCode()
|
this.toInt().hashCode()
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ public class Byte private constructor(public val value: Byte) : Number(), Compar
|
|||||||
wasm_i32_eq(this.toInt(), other.toInt())
|
wasm_i32_eq(this.toInt(), other.toInt())
|
||||||
|
|
||||||
public override fun toString(): String =
|
public override fun toString(): String =
|
||||||
TODO("Wasm: string coercion")
|
this.toInt().toString()
|
||||||
|
|
||||||
public override inline fun hashCode(): Int =
|
public override inline fun hashCode(): Int =
|
||||||
this.toInt()
|
this.toInt()
|
||||||
@@ -681,7 +681,7 @@ public class Short private constructor(public val value: Short) : Number(), Comp
|
|||||||
other is Short && wasm_i32_eq(this.toInt(), other.toInt())
|
other is Short && wasm_i32_eq(this.toInt(), other.toInt())
|
||||||
|
|
||||||
public override fun toString(): String =
|
public override fun toString(): String =
|
||||||
TODO("Wasm: string coercion")
|
this.toInt().toString()
|
||||||
|
|
||||||
public override inline fun hashCode(): Int =
|
public override inline fun hashCode(): Int =
|
||||||
this.toInt()
|
this.toInt()
|
||||||
@@ -1060,7 +1060,7 @@ public class Int private constructor(val value: Int) : Number(), Comparable<Int>
|
|||||||
other is Int && wasm_i32_eq(this, other)
|
other is Int && wasm_i32_eq(this, other)
|
||||||
|
|
||||||
public override fun toString(): String =
|
public override fun toString(): String =
|
||||||
TODO("Wasm: string coercion")
|
itoa32(this, 10)
|
||||||
|
|
||||||
public override inline fun hashCode(): Int =
|
public override inline fun hashCode(): Int =
|
||||||
this
|
this
|
||||||
@@ -1453,7 +1453,7 @@ public class Long private constructor(val value: Long) : Number(), Comparable<Lo
|
|||||||
other is Long && wasm_i64_eq(this, other)
|
other is Long && wasm_i64_eq(this, other)
|
||||||
|
|
||||||
public override fun toString(): String =
|
public override fun toString(): String =
|
||||||
TODO("Wasm: string coercion")
|
itoa64(this, 10)
|
||||||
|
|
||||||
public override fun hashCode(): Int =
|
public override fun hashCode(): Int =
|
||||||
((this ushr 32) xor this).toInt()
|
((this ushr 32) xor this).toInt()
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ public class String internal constructor(internal val chars: CharArray) : Compar
|
|||||||
|
|
||||||
internal fun stringLiteral(startAddr: Int, length: Int) = String(unsafeRawMemoryToCharArray(startAddr, length))
|
internal fun stringLiteral(startAddr: Int, length: Int) = String(unsafeRawMemoryToCharArray(startAddr, length))
|
||||||
|
|
||||||
internal fun charToString(c: Char): String = String(charArrayOf(c))
|
|
||||||
|
|
||||||
//@JsFun("(it, other) => it + String(other)")
|
//@JsFun("(it, other) => it + String(other)")
|
||||||
//private fun stringPlusImpl(it: String, other: String): String =
|
//private fun stringPlusImpl(it: String, other: String): String =
|
||||||
// implementedAsIntrinsic
|
// implementedAsIntrinsic
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.wasm.internal
|
||||||
|
|
||||||
|
private enum class CharCodes(val code: Int) {
|
||||||
|
// PERCENT(0x25),
|
||||||
|
// PLUS(0x2B),
|
||||||
|
MINUS(0x2D),
|
||||||
|
// DOT(0x2E),
|
||||||
|
_0(0x30),
|
||||||
|
// _1(0x31),
|
||||||
|
// _2(0x32),
|
||||||
|
// _3(0x33),
|
||||||
|
// _4(0x34),
|
||||||
|
// _5(0x35),
|
||||||
|
// _6(0x36),
|
||||||
|
// _7(0x37),
|
||||||
|
// _8(0x38),
|
||||||
|
// _9(0x39),
|
||||||
|
// A(0x41),
|
||||||
|
// B(0x42),
|
||||||
|
// E(0x45),
|
||||||
|
// I(0x49),
|
||||||
|
// N(0x4E),
|
||||||
|
// O(0x4F),
|
||||||
|
// X(0x58),
|
||||||
|
// Z(0x5A),
|
||||||
|
// a(0x61),
|
||||||
|
// b(0x62),
|
||||||
|
// e(0x65),
|
||||||
|
// n(0x6E),
|
||||||
|
// o(0x6F),
|
||||||
|
// u(0x75),
|
||||||
|
// x(0x78),
|
||||||
|
// z(0x7A)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun digitToChar(input: Int): Char {
|
||||||
|
assert(input in 0..9)
|
||||||
|
return (CharCodes._0.code + input).toChar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspired by the AssemblyScript implementation
|
||||||
|
internal fun itoa32(inputValue: Int, radix: Int): String {
|
||||||
|
if (radix < 2 || radix > 36)
|
||||||
|
throw IllegalArgumentException("Radix argument is unreasonable")
|
||||||
|
|
||||||
|
if (radix != 10)
|
||||||
|
TODO("When we need it")
|
||||||
|
|
||||||
|
if (inputValue == 0) return "0"
|
||||||
|
// We can't represent abs(Int.MIN_VALUE), so just hardcode it here
|
||||||
|
if (inputValue == Int.MIN_VALUE) return "-2147483648"
|
||||||
|
|
||||||
|
val sign = inputValue ushr 31
|
||||||
|
assert(sign == 1 || sign == 0)
|
||||||
|
val absValue = if (sign == 1) -inputValue else inputValue
|
||||||
|
|
||||||
|
val decimals = decimalCount32(absValue) + sign
|
||||||
|
val buf = CharArray(decimals)
|
||||||
|
utoaDecSimple(buf, absValue, decimals)
|
||||||
|
if (sign == 1)
|
||||||
|
buf[0] = CharCodes.MINUS.code.toChar()
|
||||||
|
|
||||||
|
return kotlin.String(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun utoaDecSimple(buffer: CharArray, numInput: Int, offsetInput: Int) {
|
||||||
|
assert(numInput != 0)
|
||||||
|
assert(buffer.isNotEmpty())
|
||||||
|
assert(offsetInput > 0 && offsetInput <= buffer.size)
|
||||||
|
|
||||||
|
var num = numInput
|
||||||
|
var offset = offsetInput
|
||||||
|
do {
|
||||||
|
val t = num / 10
|
||||||
|
val r = num % 10
|
||||||
|
num = t
|
||||||
|
offset--
|
||||||
|
buffer[offset] = digitToChar(r)
|
||||||
|
} while (num > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun utoaDecSimple64(buffer: CharArray, numInput: Long, offsetInput: Int) {
|
||||||
|
assert(numInput != 0L)
|
||||||
|
assert(buffer.isNotEmpty())
|
||||||
|
assert(offsetInput > 0 && offsetInput <= buffer.size)
|
||||||
|
|
||||||
|
var num = numInput
|
||||||
|
var offset = offsetInput
|
||||||
|
do {
|
||||||
|
val t = num / 10
|
||||||
|
val r = (num % 10).toInt()
|
||||||
|
num = t
|
||||||
|
offset--
|
||||||
|
buffer[offset] = digitToChar(r)
|
||||||
|
} while (num > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun Boolean.toInt() = if (this) 1 else 0
|
||||||
|
|
||||||
|
private fun decimalCount32(value: Int): Int {
|
||||||
|
if (value < 100000) {
|
||||||
|
if (value < 100) {
|
||||||
|
return 1 + (value >= 10).toInt()
|
||||||
|
} else {
|
||||||
|
return 3 + (value >= 10000).toInt() + (value >= 1000).toInt()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value < 10000000) {
|
||||||
|
return 6 + (value >= 1000000).toInt()
|
||||||
|
} else {
|
||||||
|
return 8 + (value >= 1000000000).toInt() + (value >= 100000000).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun itoa64(inputValue: Long, radix: Int): String {
|
||||||
|
if (inputValue in Int.MIN_VALUE..Int.MAX_VALUE)
|
||||||
|
return itoa32(inputValue.toInt(), radix)
|
||||||
|
|
||||||
|
if (radix < 2 || radix > 36)
|
||||||
|
throw IllegalArgumentException("Radix argument is unreasonable")
|
||||||
|
|
||||||
|
if (inputValue == 0L) return "0"
|
||||||
|
// We can't represent abs(Long.MIN_VALUE), so just hardcode it here
|
||||||
|
if (inputValue == Long.MIN_VALUE) return "-9223372036854775808"
|
||||||
|
|
||||||
|
if (radix != 10) {
|
||||||
|
TODO("When we need it")
|
||||||
|
}
|
||||||
|
|
||||||
|
val sign = (inputValue ushr 63).toInt()
|
||||||
|
assert(sign == 1 || sign == 0)
|
||||||
|
val absValue = if (sign == 1) -inputValue else inputValue
|
||||||
|
|
||||||
|
val decimals = decimalCount64High(absValue) + sign
|
||||||
|
val buf = CharArray(decimals)
|
||||||
|
utoaDecSimple64(buf, absValue, decimals)
|
||||||
|
if (sign == 1)
|
||||||
|
buf[0] = CharCodes.MINUS.code.toChar()
|
||||||
|
|
||||||
|
return kotlin.String(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count number of decimals for u64 values
|
||||||
|
// In our case input value always greater than 2^32-1 so we can skip some parts
|
||||||
|
private fun decimalCount64High(value: Long): Int {
|
||||||
|
if (value < 1000000000000000) {
|
||||||
|
if (value < 1000000000000) {
|
||||||
|
return 10 + (value >= 100000000000).toInt() + (value >= 10000000000).toInt()
|
||||||
|
} else {
|
||||||
|
return 13 + (value >= 100000000000000).toInt() + (value >= 10000000000000).toInt()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value < 100000000000000000) {
|
||||||
|
return 16 + (value >= 10000000000000000).toInt()
|
||||||
|
} else {
|
||||||
|
return 18 + (value >= 1000000000000000000).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user