diff --git a/browser-example/build.gradle.kts b/browser-example/build.gradle.kts index de77ccc..6f3542a 100644 --- a/browser-example/build.gradle.kts +++ b/browser-example/build.gradle.kts @@ -1,8 +1,8 @@ import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig plugins { - kotlin("multiplatform") version "1.9.20" - // kotlin("multiplatform") version "2.0.0-Beta1" + kotlin("multiplatform") version "1.9.22" +// kotlin("multiplatform") version "2.0.0-Beta2" } group = "me.user" diff --git a/browser-example/src/wasmJsMain/kotlin/LongSparseArray.kt b/browser-example/src/wasmJsMain/kotlin/LongSparseArray.kt new file mode 100644 index 0000000..e08d501 --- /dev/null +++ b/browser-example/src/wasmJsMain/kotlin/LongSparseArray.kt @@ -0,0 +1,74 @@ +internal val EMPTY_LONGS = LongArray(0) +internal val EMPTY_OBJECTS = arrayOfNulls(0) + +public open class LongSparseArray public constructor(initialCapacity: Int) { + internal var garbage = false + internal var keys: LongArray + internal var values: Array + internal var size = 0 + + init { + if (initialCapacity == 0) { + keys = EMPTY_LONGS + values = EMPTY_OBJECTS + } else { + val idealCapacity = 10 + keys = LongArray(idealCapacity) + values = arrayOfNulls(idealCapacity) + } + } + public open operator fun get(key: Long): E? = commonGet(key) + @Suppress("KotlinOperator") // Avoid confusion with matrix access syntax. + public open fun get(key: Long, defaultValue: E): E = commonGet(key, defaultValue) + public open fun put(key: Long, value: E): Unit = commonPut(key, value) +} + + +private val DELETED = Any() + +@Suppress("NOTHING_TO_INLINE") +internal inline fun LongSparseArray.commonGet(key: Long): E? { + // @Suppress("UNCHECKED_CAST") + return commonGetInternal(key, null) // as E? +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun LongSparseArray.commonGet(key: Long, defaultValue: E): E { + // @Suppress("UNCHECKED_CAST") + return commonGetInternal(key, defaultValue) // as E +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun LongSparseArray.commonGetInternal( + key: Long, + defaultValue: T +): T { + val i = key.toInt() + return if (i < 0 || values[i] === DELETED) { // without this `if`, it doesn't crash + defaultValue + } else { + @Suppress("UNCHECKED_CAST") + values[key.toInt()] as T + } // as T // casting here helps too +} + +// This is a workaround we use in Compose sources + +//@Suppress("NOTHING_TO_INLINE") +//internal inline fun LongSparseArray<*>.commonGetInternal( +// key: Long, +// defaultValue: Any? +//): Any? { +// val i = key.toInt() +// return if (i < 0 || values[i] === DELETED) { +// defaultValue +// } else { +// values[i] +// } +//} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun LongSparseArray.commonPut(key: Long, value: E) { + values[key.toInt()] = value + return +} \ No newline at end of file diff --git a/browser-example/src/wasmJsTest/kotlin/TestLongSparseArray.kt b/browser-example/src/wasmJsTest/kotlin/TestLongSparseArray.kt new file mode 100644 index 0000000..01d5966 --- /dev/null +++ b/browser-example/src/wasmJsTest/kotlin/TestLongSparseArray.kt @@ -0,0 +1,14 @@ +import kotlin.test.Test +import kotlin.test.assertEquals + +class TestLongSparseArray { + + @Test + fun itCrashes() { + val lsa = LongSparseArray(10) + lsa.put(1, "a") + lsa.put(2, "b") + lsa.put(3, "c") + assertEquals("a", lsa.get(1)) + } +} \ No newline at end of file