Skip to content

Commit 2e8ce65

Browse files
committed
[K/JS] Optimize copyOf(newSize) function for primitive arrays
All primitive arrays - apart from LongArray and BooleanArray - are compiled to JS TypedArrays. This means that instead of iterating all indexes we can simply use TypedArray.set or TypedArray.slice depending on the inputted new size. ^KT-77646
1 parent 7f600d7 commit 2e8ce65

File tree

2 files changed

+73
-14
lines changed

2 files changed

+73
-14
lines changed

libraries/stdlib/js/src/generated/_ArraysJs.kt

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,13 @@ public fun <T> Array<out T>.copyOf(newSize: Int): Array<T?> {
940940
*/
941941
public actual fun ByteArray.copyOf(newSize: Int): ByteArray {
942942
require(newSize >= 0) { "Invalid new array size: $newSize." }
943-
return fillFrom(this, ByteArray(newSize))
943+
return if (newSize > this.size) {
944+
ByteArray(newSize).also { copy ->
945+
copy.asDynamic().set(this, 0)
946+
}
947+
} else {
948+
this.asDynamic().slice(0, newSize)
949+
}
944950
}
945951

946952
/**
@@ -954,7 +960,13 @@ public actual fun ByteArray.copyOf(newSize: Int): ByteArray {
954960
*/
955961
public actual fun ShortArray.copyOf(newSize: Int): ShortArray {
956962
require(newSize >= 0) { "Invalid new array size: $newSize." }
957-
return fillFrom(this, ShortArray(newSize))
963+
return if (newSize > this.size) {
964+
ShortArray(newSize).also { copy ->
965+
copy.asDynamic().set(this, 0)
966+
}
967+
} else {
968+
this.asDynamic().slice(0, newSize)
969+
}
958970
}
959971

960972
/**
@@ -968,7 +980,13 @@ public actual fun ShortArray.copyOf(newSize: Int): ShortArray {
968980
*/
969981
public actual fun IntArray.copyOf(newSize: Int): IntArray {
970982
require(newSize >= 0) { "Invalid new array size: $newSize." }
971-
return fillFrom(this, IntArray(newSize))
983+
return if (newSize > this.size) {
984+
IntArray(newSize).also { copy ->
985+
copy.asDynamic().set(this, 0)
986+
}
987+
} else {
988+
this.asDynamic().slice(0, newSize)
989+
}
972990
}
973991

974992
/**
@@ -996,7 +1014,13 @@ public actual fun LongArray.copyOf(newSize: Int): LongArray {
9961014
*/
9971015
public actual fun FloatArray.copyOf(newSize: Int): FloatArray {
9981016
require(newSize >= 0) { "Invalid new array size: $newSize." }
999-
return fillFrom(this, FloatArray(newSize))
1017+
return if (newSize > this.size) {
1018+
FloatArray(newSize).also { copy ->
1019+
copy.asDynamic().set(this, 0)
1020+
}
1021+
} else {
1022+
this.asDynamic().slice(0, newSize)
1023+
}
10001024
}
10011025

10021026
/**
@@ -1010,7 +1034,13 @@ public actual fun FloatArray.copyOf(newSize: Int): FloatArray {
10101034
*/
10111035
public actual fun DoubleArray.copyOf(newSize: Int): DoubleArray {
10121036
require(newSize >= 0) { "Invalid new array size: $newSize." }
1013-
return fillFrom(this, DoubleArray(newSize))
1037+
return if (newSize > this.size) {
1038+
DoubleArray(newSize).also { copy ->
1039+
copy.asDynamic().set(this, 0)
1040+
}
1041+
} else {
1042+
this.asDynamic().slice(0, newSize)
1043+
}
10141044
}
10151045

10161046
/**
@@ -1038,7 +1068,14 @@ public actual fun BooleanArray.copyOf(newSize: Int): BooleanArray {
10381068
*/
10391069
public actual fun CharArray.copyOf(newSize: Int): CharArray {
10401070
require(newSize >= 0) { "Invalid new array size: $newSize." }
1041-
return withType("CharArray", fillFrom(this, CharArray(newSize)))
1071+
val copy = if (newSize > this.size) {
1072+
CharArray(newSize).also { copy ->
1073+
copy.asDynamic().set(this, 0)
1074+
}
1075+
} else {
1076+
this.asDynamic().slice(0, newSize)
1077+
}
1078+
return withType("CharArray", copy)
10421079
}
10431080

10441081
/**

libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,14 +1076,36 @@ object ArrayOps : TemplateGroupBase() {
10761076
returns("SELF")
10771077
on(Platform.JS) {
10781078
when (primitive!!) {
1079-
PrimitiveType.Boolean ->
1080-
body { "return withType(\"BooleanArray\", arrayCopyResize(this, newSize, false))" }
1081-
PrimitiveType.Char ->
1082-
body { "return withType(\"CharArray\", fillFrom(this, ${primitive}Array(newSize)))" }
1083-
PrimitiveType.Long ->
1084-
body { "return withType(\"LongArray\", arrayCopyResize(this, newSize, ${primitive!!.zero()}))" }
1085-
else ->
1086-
body { "return fillFrom(this, ${primitive}Array(newSize))" }
1079+
PrimitiveType.Long -> body {
1080+
"return withType(\"LongArray\", arrayCopyResize(this, newSize, ${primitive!!.zero()}))"
1081+
}
1082+
PrimitiveType.Boolean -> body {
1083+
"return withType(\"BooleanArray\", arrayCopyResize(this, newSize, false))"
1084+
}
1085+
PrimitiveType.Char -> body {
1086+
"""
1087+
val copy = if (newSize > this.size) {
1088+
CharArray(newSize).also { copy ->
1089+
copy.asDynamic().set(this, 0)
1090+
}
1091+
} else {
1092+
this.asDynamic().slice(0, newSize)
1093+
}
1094+
1095+
return withType("CharArray", copy)
1096+
""".trimIndent()
1097+
}
1098+
else -> body {
1099+
"""
1100+
return if (newSize > this.size) {
1101+
${primitive}Array(newSize).also { copy ->
1102+
copy.asDynamic().set(this, 0)
1103+
}
1104+
} else {
1105+
this.asDynamic().slice(0, newSize)
1106+
}
1107+
""".trimIndent()
1108+
}
10871109
}
10881110
body { newSizeCheck + "\n" + body }
10891111
}

0 commit comments

Comments
 (0)