Specialize contentDeepEquals/HashCode/ToString for arrays of unsigned types

#KT-26388
This commit is contained in:
Ilya Gorbunov
2018-09-12 02:41:27 +03:00
parent 3cc606577c
commit 2d356b89b5
8 changed files with 208 additions and 47 deletions
@@ -65,3 +65,95 @@ public inline fun Array<*>?.isNullOrEmpty(): Boolean {
@Suppress("UPPER_BOUND_CANNOT_BE_ARRAY")
public inline fun <C, R> C.ifEmpty(defaultValue: () -> R): R where C : Array<*>, C : R =
if (isEmpty()) defaultValue() else this
@SinceKotlin("1.3")
@PublishedApi
@kotlin.jvm.JvmName("contentDeepEquals")
@kotlin.js.JsName("contentDeepEqualsImpl")
internal fun <T> Array<out T>.contentDeepEqualsImpl(other: Array<out T>): Boolean {
if (this === other) return true
if (this.size != other.size) return false
for (i in indices) {
val v1 = this[i]
val v2 = other[i]
if (v1 === v2) {
continue
} else if (v1 == null || v2 == null) {
return false
}
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
v1 is UByteArray && v2 is UByteArray -> if (!v1.contentEquals(v2)) return false
v1 is UShortArray && v2 is UShortArray -> if (!v1.contentEquals(v2)) return false
v1 is UIntArray && v2 is UIntArray -> if (!v1.contentEquals(v2)) return false
v1 is ULongArray && v2 is ULongArray -> if (!v1.contentEquals(v2)) return false
else -> if (v1 != v2) return false
}
}
return true
}
@SinceKotlin("1.3")
@PublishedApi
@kotlin.jvm.JvmName("contentDeepToString")
@kotlin.js.JsName("contentDeepToStringImpl")
internal fun <T> Array<out T>.contentDeepToStringImpl(): String {
val length = size.coerceAtMost((Int.MAX_VALUE - 2) / 5) * 5 + 2 // in order not to overflow Int.MAX_VALUE
return buildString(length) {
contentDeepToStringInternal(this, mutableSetOf())
}
}
@UseExperimental(ExperimentalUnsignedTypes::class)
private fun <T> Array<out T>.contentDeepToStringInternal(result: StringBuilder, processed: MutableSet<Array<*>>) {
if (this in processed) {
result.append("[...]")
return
}
processed.add(this)
result.append('[')
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())
is UByteArray -> result.append(element.contentToString())
is UShortArray -> result.append(element.contentToString())
is UIntArray -> result.append(element.contentToString())
is ULongArray -> result.append(element.contentToString())
else -> result.append(element.toString())
}
}
result.append(']')
processed.remove(this)
}