[WASM] Wasm string.plus optimisations
This commit is contained in:
@@ -103,7 +103,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 =
|
||||||
String.unsafeFromCharArray(WasmCharArray(1).also { it.set(0, this) })
|
String(WasmCharArray(1).also { it.set(0, this) })
|
||||||
|
|
||||||
override fun hashCode(): Int =
|
override fun hashCode(): Int =
|
||||||
this.toInt().hashCode()
|
this.toInt().hashCode()
|
||||||
|
|||||||
@@ -12,30 +12,31 @@ import kotlin.math.min
|
|||||||
* The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
|
* The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
|
||||||
* implemented as instances of this class.
|
* implemented as instances of this class.
|
||||||
*/
|
*/
|
||||||
public class String private constructor(internal val chars: WasmCharArray) : Comparable<String>, CharSequence {
|
public class String private constructor(
|
||||||
public companion object {
|
private var leftIfInSum: String?,
|
||||||
// Note: doesn't copy the array, use with care.
|
private var _chars: WasmCharArray,
|
||||||
internal fun unsafeFromCharArray(chars: WasmCharArray) = String(chars)
|
) : Comparable<String>, CharSequence {
|
||||||
}
|
public companion object {}
|
||||||
|
|
||||||
|
internal constructor(chars: WasmCharArray) : this(null, chars) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
|
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
|
||||||
*/
|
*/
|
||||||
public operator fun plus(other: Any?): String {
|
public operator fun plus(other: Any?): String {
|
||||||
val thisChars = chars
|
val right = if (other is String) other else other.toString()
|
||||||
val otherChars = if (other is String) other.chars else other.toString().chars
|
return String(this, right.chars)
|
||||||
val thisLen = thisChars.len()
|
|
||||||
val otherLen = otherChars.len()
|
|
||||||
if (otherLen == 0) return String(thisChars)
|
|
||||||
|
|
||||||
val newChars = WasmCharArray(thisLen + otherLen)
|
|
||||||
copyWasmArray(thisChars, newChars, 0, 0, thisLen)
|
|
||||||
copyWasmArray(otherChars, newChars, 0, thisLen, otherLen)
|
|
||||||
return String(newChars)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override val length: Int
|
public override val length: Int get() {
|
||||||
get() = chars.len()
|
var currentLeftString = leftIfInSum
|
||||||
|
var currentLength = _chars.len()
|
||||||
|
while (currentLeftString != null) {
|
||||||
|
currentLength += currentLeftString._chars.len()
|
||||||
|
currentLeftString = currentLeftString.leftIfInSum
|
||||||
|
}
|
||||||
|
return currentLength
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the character of this string at the specified [index].
|
* Returns the character of this string at the specified [index].
|
||||||
@@ -44,8 +45,36 @@ public class String private constructor(internal val chars: WasmCharArray) : Com
|
|||||||
* where the behavior is unspecified.
|
* where the behavior is unspecified.
|
||||||
*/
|
*/
|
||||||
public override fun get(index: Int): Char {
|
public override fun get(index: Int): Char {
|
||||||
if (index < 0 || index >= chars.len()) throw IndexOutOfBoundsException()
|
if (index < 0) throw IndexOutOfBoundsException()
|
||||||
return chars.get(index)
|
val folded = chars
|
||||||
|
val length = folded.len()
|
||||||
|
if (index >= length) throw IndexOutOfBoundsException()
|
||||||
|
return folded.get(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun foldChars() {
|
||||||
|
val stringLength = this.length
|
||||||
|
val newArray = WasmCharArray(stringLength)
|
||||||
|
|
||||||
|
var currentStartIndex = stringLength
|
||||||
|
var currentLeftString: String? = this
|
||||||
|
while (currentLeftString != null) {
|
||||||
|
val currentLeftStringChars = currentLeftString._chars
|
||||||
|
val currentLeftStringLen = currentLeftStringChars.len()
|
||||||
|
currentStartIndex -= currentLeftStringLen
|
||||||
|
copyWasmArray(currentLeftStringChars, newArray, 0, currentStartIndex, currentLeftStringLen)
|
||||||
|
currentLeftString = currentLeftString.leftIfInSum
|
||||||
|
}
|
||||||
|
check(currentStartIndex == 0)
|
||||||
|
_chars = newArray
|
||||||
|
leftIfInSum = null
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline val chars: WasmCharArray get() {
|
||||||
|
if (leftIfInSum != null) {
|
||||||
|
foldChars()
|
||||||
|
}
|
||||||
|
return _chars
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
||||||
@@ -84,17 +113,18 @@ public class String private constructor(internal val chars: WasmCharArray) : Com
|
|||||||
public override fun toString(): String = this
|
public override fun toString(): String = this
|
||||||
|
|
||||||
public override fun hashCode(): Int {
|
public override fun hashCode(): Int {
|
||||||
val thisLength = length
|
if (_hashCode != 0) return _hashCode
|
||||||
|
val thisChars = chars
|
||||||
if (_hashCode != 0 || thisLength == null)
|
val thisLength = thisChars.len()
|
||||||
return _hashCode
|
if (thisLength == 0) return 0
|
||||||
|
|
||||||
var hash = 0
|
var hash = 0
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < thisLength) {
|
while (i < thisLength) {
|
||||||
hash = 31 * hash + chars.get(i).toInt()
|
hash = 31 * hash + thisChars.get(i).toInt()
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
_hashCode = hash
|
_hashCode = hash
|
||||||
return _hashCode
|
return _hashCode
|
||||||
}
|
}
|
||||||
@@ -103,5 +133,5 @@ public class String private constructor(internal val chars: WasmCharArray) : Com
|
|||||||
internal fun stringLiteral(startAddr: Int, length: Int): String {
|
internal fun stringLiteral(startAddr: Int, length: Int): String {
|
||||||
val array = WasmCharArray(length)
|
val array = WasmCharArray(length)
|
||||||
unsafeRawMemoryToWasmCharArray(startAddr, 0, length, array)
|
unsafeRawMemoryToWasmCharArray(startAddr, 0, length, array)
|
||||||
return String.unsafeFromCharArray(array)
|
return String(array)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
|
|||||||
val stringLength = stringLength(x)
|
val stringLength = stringLength(x)
|
||||||
val dstArray = WasmCharArray(stringLength)
|
val dstArray = WasmCharArray(stringLength)
|
||||||
if (stringLength == 0) {
|
if (stringLength == 0) {
|
||||||
return String.unsafeFromCharArray(dstArray)
|
return String(dstArray)
|
||||||
}
|
}
|
||||||
val maxStringLength = unsafeGetScratchRawMemorySize() / CHAR_SIZE_BYTES
|
val maxStringLength = unsafeGetScratchRawMemorySize() / CHAR_SIZE_BYTES
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
|
|||||||
|
|
||||||
jsExportStringToWasm(x, srcStartIndex, stringLength - srcStartIndex, memBuffer)
|
jsExportStringToWasm(x, srcStartIndex, stringLength - srcStartIndex, memBuffer)
|
||||||
unsafeRawMemoryToWasmCharArray(memBuffer, srcStartIndex, stringLength - srcStartIndex, dstArray)
|
unsafeRawMemoryToWasmCharArray(memBuffer, srcStartIndex, stringLength - srcStartIndex, dstArray)
|
||||||
return String.unsafeFromCharArray(dstArray)
|
return String(dstArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ internal fun itoa32(inputValue: Int, radix: Int): String {
|
|||||||
if (sign == 1)
|
if (sign == 1)
|
||||||
buf.set(0, CharCodes.MINUS.code.toChar())
|
buf.set(0, CharCodes.MINUS.code.toChar())
|
||||||
|
|
||||||
return String.unsafeFromCharArray(buf)
|
return String(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun utoaDecSimple(buffer: WasmCharArray, numInput: Int, offsetInput: Int) {
|
private fun utoaDecSimple(buffer: WasmCharArray, numInput: Int, offsetInput: Int) {
|
||||||
@@ -144,7 +144,7 @@ internal fun itoa64(inputValue: Long, radix: Int): String {
|
|||||||
if (sign == 1)
|
if (sign == 1)
|
||||||
buf.set(0, CharCodes.MINUS.code.toChar())
|
buf.set(0, CharCodes.MINUS.code.toChar())
|
||||||
|
|
||||||
return String.unsafeFromCharArray(buf)
|
return String(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count number of decimals for u64 values
|
// Count number of decimals for u64 values
|
||||||
@@ -178,7 +178,7 @@ internal fun dtoa(value: Double): String {
|
|||||||
val size = dtoaCore(buf, value)
|
val size = dtoaCore(buf, value)
|
||||||
val ret = WasmCharArray(size)
|
val ret = WasmCharArray(size)
|
||||||
buf.copyInto(ret, 0, 0, size)
|
buf.copyInto(ret, 0, 0, size)
|
||||||
return String.unsafeFromCharArray(ret)
|
return String(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dtoaCore(buffer: WasmCharArray, valueInp: Double): Int {
|
private fun dtoaCore(buffer: WasmCharArray, valueInp: Double): Int {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ internal fun insertString(array: CharArray, destinationIndex: Int, value: String
|
|||||||
internal fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int): String {
|
internal fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int): String {
|
||||||
val copy = WasmCharArray(size)
|
val copy = WasmCharArray(size)
|
||||||
copyWasmArray(array.storage, copy, start, 0, size)
|
copyWasmArray(array.storage, copy, start, 0, size)
|
||||||
return String.unsafeFromCharArray(copy)
|
return String(copy)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun insertInt(array: CharArray, start: Int, value: Int): Int {
|
internal fun insertInt(array: CharArray, start: Int, value: Int): Int {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public actual fun String(chars: CharArray, offset: Int, length: Int): String {
|
|||||||
|
|
||||||
val copy = WasmCharArray(length)
|
val copy = WasmCharArray(length)
|
||||||
copyWasmArray(chars.storage, copy, offset, 0, length)
|
copyWasmArray(chars.storage, copy, offset, 0, length)
|
||||||
return String.unsafeFromCharArray(copy)
|
return String(copy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,7 +88,7 @@ public actual fun CharArray.concatToString(): String {
|
|||||||
val thisLength = thisStorage.len()
|
val thisLength = thisStorage.len()
|
||||||
val copy = WasmCharArray(thisLength)
|
val copy = WasmCharArray(thisLength)
|
||||||
copyWasmArray(this.storage, copy, 0, 0, thisLength)
|
copyWasmArray(this.storage, copy, 0, 0, thisLength)
|
||||||
return String.unsafeFromCharArray(copy)
|
return String(copy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +109,7 @@ public actual fun CharArray.concatToString(startIndex: Int = 0, endIndex: Int =
|
|||||||
val length = endIndex - startIndex
|
val length = endIndex - startIndex
|
||||||
val copy = WasmCharArray(length)
|
val copy = WasmCharArray(length)
|
||||||
copyWasmArray(this.storage, copy, startIndex, 0, length)
|
copyWasmArray(this.storage, copy, startIndex, 0, length)
|
||||||
return String.unsafeFromCharArray(copy)
|
return String(copy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user