/* * Copyright 2010-2019 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 import kotlin.wasm.internal.* import kotlin.math.min /** * The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are * implemented as instances of this class. */ public class String internal @WasmPrimitiveConstructor constructor( private var leftIfInSum: String?, @kotlin.internal.IntrinsicConstEvaluation public override val length: Int, private var _chars: WasmCharArray, ) : Comparable, CharSequence { public companion object {} /** * Returns a string obtained by concatenating this string with the string representation of the given [other] object. */ @kotlin.internal.IntrinsicConstEvaluation public operator fun plus(other: Any?): String { val right = other.toString() return String(this, this.length + right.length, right.chars) } /** * Returns the character of this string at the specified [index]. * * If the [index] is out of bounds of this string, throws an [IndexOutOfBoundsException] except in Kotlin/JS * where the behavior is unspecified. */ @kotlin.internal.IntrinsicConstEvaluation public override fun get(index: Int): Char { rangeCheck(index, this.length) return chars.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 { val actualStartIndex = startIndex.coerceAtLeast(0) val actualEndIndex = endIndex.coerceAtMost(this.length) val newLength = actualEndIndex - actualStartIndex if (newLength <= 0) return "" val newChars = WasmCharArray(newLength) copyWasmArray(chars, newChars, actualStartIndex, 0, newLength) return newChars.createString() } @kotlin.internal.IntrinsicConstEvaluation public override fun compareTo(other: String): Int { if (this === other) return 0 val thisChars = this.chars val otherChars = other.chars val thisLength = thisChars.len() val otherLength = otherChars.len() val minimumLength = if (thisLength < otherLength) thisLength else otherLength repeat(minimumLength) { val l = thisChars.get(it) val r = otherChars.get(it) if (l != r) return l - r } return thisLength - otherLength } @kotlin.internal.IntrinsicConstEvaluation public override fun equals(other: Any?): Boolean { if (other == null) return false if (other === this) return true val otherString = other as? String ?: return false val thisLength = this.length val otherLength = otherString.length if (thisLength != otherLength) return false val thisHash = this._hashCode val otherHash = other._hashCode if (thisHash != otherHash && thisHash != 0 && otherHash != 0) return false val thisChars = this.chars val otherChars = other.chars repeat(thisLength) { if (thisChars.get(it) != otherChars.get(it)) return false } return true } @kotlin.internal.IntrinsicConstEvaluation public override fun toString(): String = this public override fun hashCode(): Int { if (_hashCode != 0) return _hashCode val thisLength = this.length if (thisLength == 0) return 0 val thisChars = chars var hash = 0 repeat(thisLength) { hash = (hash shl 5) - hash + thisChars.get(it).code } _hashCode = hash return _hashCode } } @Suppress("NOTHING_TO_INLINE") internal inline fun WasmCharArray.createString(): String = String(null, this.len(), this) internal fun stringLiteral(poolId: Int, startAddress: Int, length: Int): String { val cached = stringPool[poolId] if (cached !== null) { return cached } val chars = array_new_data0(startAddress, length) val newString = String(null, length, chars) stringPool[poolId] = newString return newString }