diff --git a/runtime/src/main/kotlin/kotlin/Arrays.kt b/runtime/src/main/kotlin/kotlin/Arrays.kt index c5d39975baa..7875f4fc9b2 100644 --- a/runtime/src/main/kotlin/kotlin/Arrays.kt +++ b/runtime/src/main/kotlin/kotlin/Arrays.kt @@ -11450,36 +11450,44 @@ public inline fun Array.subarrayContentToString(offset: Int, length: */ @SinceKotlin("1.1") public infix fun Array.contentDeepEquals(other: Array): Boolean { - if (this === other) + if (this === other) { return true + } - if (size != other.size) + if (this.size != other.size) { return false + } for (i in indices) { - val e1 = this[i] - val e2 = other[i] + val v1 = this[i] + val v2 = other[i] - if (e1 === e2) - continue - if (e1 == null) - return false - - // Figure out whether the two elements are equal - val eq = when { - e1 is Array<*> && e2 is Array<*> -> e1 contentDeepEquals e2 - e1 is ByteArray && e2 is ByteArray -> e1 contentEquals e2 - e1 is ShortArray && e2 is ShortArray -> e1 contentEquals e2 - e1 is IntArray && e2 is IntArray -> e1 contentEquals e2 - e1 is LongArray && e2 is LongArray -> e1 contentEquals e2 - e1 is CharArray && e2 is CharArray -> e1 contentEquals e2 - e1 is FloatArray && e2 is FloatArray -> e1 contentEquals e2 - e1 is DoubleArray && e2 is DoubleArray -> e1 contentEquals e2 - e1 is BooleanArray && e2 is BooleanArray -> e1 contentEquals e2 - else -> e1 == e2 + if (v1 == null || v2 == null) { + if (v1 == v2) { + continue + } else { + return false + } + } + + // TODO: Do a typecheck like if(v1.class == v2.class) return false + // Cases: + // Array + // Primitive array + // Some value (not an array) + + when { + v1 is Array<*> && v2 is Array<*> -> if (!v1.contentDeepEquals(v2)) return false + v1 is ByteArray && v2 is ByteArray -> if (!v1.contentEquals(v2)) return false + v1 is ShortArray && v2 is ShortArray -> if (!v1.contentEquals(v2)) return false + v1 is IntArray && v2 is IntArray -> if (!v1.contentEquals(v2)) return false + v1 is LongArray && v2 is LongArray -> if (!v1.contentEquals(v2)) return false + v1 is FloatArray && v2 is FloatArray -> if (!v1.contentEquals(v2)) return false + v1 is DoubleArray && v2 is DoubleArray -> if (!v1.contentEquals(v2)) return false + v1 is CharArray && v2 is CharArray -> if (!v1.contentEquals(v2)) return false + v1 is BooleanArray && v2 is BooleanArray -> if (!v1.contentEquals(v2)) return false + else -> if (v1 != v2) return false } - if (!eq) - return false } return true @@ -11515,56 +11523,42 @@ public fun Array.contentDeepHashCode(): Int { */ @SinceKotlin("1.1") public fun Array.contentDeepToString(): String { - var bufLen = 20 * size - if (size != 0 && bufLen <= 0) - bufLen = Int.MAX_VALUE - val buf = StringBuilder(bufLen) - contentDeepToString(buf, mutableSetOf()) - return buf.toString() + val length = if (size * 5 + 2 > 0) size * 5 + 2 else Int.MAX_VALUE + val result = StringBuilder(length) + contentDeepToStringInternal(result, mutableSetOf()) + return result.toString() } -/** - * Internal recursive function to build a string for [contentDeepToString]. - */ -private fun Array.contentDeepToString(buf: StringBuilder, dejaVu: MutableSet>) { - if (size == 0) { - buf.append("[]") +private fun Array.contentDeepToStringInternal(result: StringBuilder, processed: MutableSet>) { + if (this in processed) { + result.append("[...]") return } + processed.add(this) + result.append('[') - val iMax = size - 1 - @Suppress("UNCHECKED_CAST") - dejaVu.add(this as Array) // TODO: Is the cast correct? - buf.append('[') - var i = 0 - while (true) { - val element = this[i] - when { - element is Array<*> -> { - @Suppress("UNCHECKED_CAST") - if (dejaVu.contains(element as Array)) { - buf.append("[...]") - } else { - element.contentDeepToString(buf, dejaVu) - } - } - element is ByteArray -> buf.append(element.contentToString()) - element is ShortArray -> buf.append(element.contentToString()) - element is IntArray -> buf.append(element.contentToString()) - element is LongArray -> buf.append(element.contentToString()) - element is CharArray -> buf.append(element.contentToString()) - element is FloatArray -> buf.append(element.contentToString()) - element is DoubleArray -> buf.append(element.contentToString()) - element is BooleanArray -> buf.append(element.contentToString()) - else -> buf.append(element.toString()) + for (i in indices) { + if (i != 0) { + result.append(", ") + } + val element = this[i] + when (element) { + null -> result.append("null") + is Array<*> -> element.contentDeepToStringInternal(result, processed) + is ByteArray -> result.append(element.contentToString()) + is ShortArray -> result.append(element.contentToString()) + is IntArray -> result.append(element.contentToString()) + is LongArray -> result.append(element.contentToString()) + is FloatArray -> result.append(element.contentToString()) + is DoubleArray -> result.append(element.contentToString()) + is CharArray -> result.append(element.contentToString()) + is BooleanArray -> result.append(element.contentToString()) + else -> result.append(element.toString()) } - if (i == iMax) - break - buf.append(", ") - i++ } - buf.append(']') - dejaVu.remove(this) + + result.append(']') + processed.remove(this) } /**