Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 49 additions & 6 deletions libraries/stdlib/js/src/generated/_ArraysJs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,14 @@ public fun <T> Array<out T>.copyOf(newSize: Int): Array<T?> {
*/
public actual fun ByteArray.copyOf(newSize: Int): ByteArray {
require(newSize >= 0) { "Invalid new array size: $newSize." }
return fillFrom(this, ByteArray(newSize))
val size = this.size
return when {
newSize < 16 || size < 16 -> fillFrom(this, ByteArray(newSize))
newSize > size -> ByteArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
}

/**
Expand All @@ -954,7 +961,14 @@ public actual fun ByteArray.copyOf(newSize: Int): ByteArray {
*/
public actual fun ShortArray.copyOf(newSize: Int): ShortArray {
require(newSize >= 0) { "Invalid new array size: $newSize." }
return fillFrom(this, ShortArray(newSize))
val size = this.size
return when {
newSize < 16 || size < 16 -> fillFrom(this, ShortArray(newSize))
newSize > size -> ShortArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
}

/**
Expand All @@ -968,7 +982,14 @@ public actual fun ShortArray.copyOf(newSize: Int): ShortArray {
*/
public actual fun IntArray.copyOf(newSize: Int): IntArray {
require(newSize >= 0) { "Invalid new array size: $newSize." }
return fillFrom(this, IntArray(newSize))
val size = this.size
return when {
newSize < 16 || size < 16 -> fillFrom(this, IntArray(newSize))
newSize > size -> IntArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
}

/**
Expand Down Expand Up @@ -996,7 +1017,14 @@ public actual fun LongArray.copyOf(newSize: Int): LongArray {
*/
public actual fun FloatArray.copyOf(newSize: Int): FloatArray {
require(newSize >= 0) { "Invalid new array size: $newSize." }
return fillFrom(this, FloatArray(newSize))
val size = this.size
return when {
newSize < 16 || size < 16 -> fillFrom(this, FloatArray(newSize))
newSize > size -> FloatArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
}

/**
Expand All @@ -1010,7 +1038,14 @@ public actual fun FloatArray.copyOf(newSize: Int): FloatArray {
*/
public actual fun DoubleArray.copyOf(newSize: Int): DoubleArray {
require(newSize >= 0) { "Invalid new array size: $newSize." }
return fillFrom(this, DoubleArray(newSize))
val size = this.size
return when {
newSize < 16 || size < 16 -> fillFrom(this, DoubleArray(newSize))
newSize > size -> DoubleArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
}

/**
Expand Down Expand Up @@ -1038,7 +1073,15 @@ public actual fun BooleanArray.copyOf(newSize: Int): BooleanArray {
*/
public actual fun CharArray.copyOf(newSize: Int): CharArray {
require(newSize >= 0) { "Invalid new array size: $newSize." }
return withType("CharArray", fillFrom(this, CharArray(newSize)))
val size = this.size
val copy = when {
newSize < 16 || size < 16 -> fillFrom(this, CharArray(newSize))
newSize > size -> CharArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
return withType("CharArray", copy)
}

/**
Expand Down
43 changes: 35 additions & 8 deletions libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1076,14 +1076,41 @@ object ArrayOps : TemplateGroupBase() {
returns("SELF")
on(Platform.JS) {
when (primitive!!) {
PrimitiveType.Boolean ->
body { "return withType(\"BooleanArray\", arrayCopyResize(this, newSize, false))" }
PrimitiveType.Char ->
body { "return withType(\"CharArray\", fillFrom(this, ${primitive}Array(newSize)))" }
PrimitiveType.Long ->
body { "return withType(\"LongArray\", arrayCopyResize(this, newSize, ${primitive!!.zero()}))" }
else ->
body { "return fillFrom(this, ${primitive}Array(newSize))" }
PrimitiveType.Long -> body {
"return withType(\"LongArray\", arrayCopyResize(this, newSize, ${primitive!!.zero()}))"
}
PrimitiveType.Boolean -> body {
"return withType(\"BooleanArray\", arrayCopyResize(this, newSize, false))"
}
// Benchmarking showed that when copying a small number of elements (typically < 20),
// a simple loop is consistently faster than calling TypedArray.set or TypedArray.slice
// across JS engines. We chose 16 as an arbitrary threshold based on those results.
PrimitiveType.Char -> body {
"""
val size = this.size
val copy = when {
newSize < 16 || size < 16 -> fillFrom(this, CharArray(newSize))
newSize > size -> CharArray(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}

return withType("CharArray", copy)
""".trimIndent()
}
else -> body {
"""
val size = this.size
return when {
newSize < 16 || size < 16 -> fillFrom(this, ${primitive}Array(newSize))
newSize > size -> ${primitive}Array(newSize).also { copy ->
copy.asDynamic().set(this, 0)
}
else -> this.asDynamic().slice(0, newSize)
}
""".trimIndent()
}
}
body { newSizeCheck + "\n" + body }
}
Expand Down