From 9db74023f9fca7e8c9a70468deaaf799bd12af33 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Thu, 2 May 2024 17:41:46 -0400 Subject: [PATCH] refactor: Swap atomifcfu for touchlab/Stately due to JVM 21 issues --- addons/geary-prefabs/build.gradle.kts | 3 --- build.gradle.kts | 1 + geary-benchmarks/build.gradle.kts | 2 +- geary-core/build.gradle.kts | 8 +------- .../mineinabyss/geary/datatypes/EntityStack.kt | 9 ++++++--- .../geary/datatypes/maps/SynchronizedTypeMap.kt | 15 ++++++++------- .../engine/archetypes/ArchetypeQueryManager.kt | 10 +++++----- .../archetypes/ComponentAsEntityProvider.kt | 12 ++++++------ .../archetypes/EntityByArchetypeProvider.kt | 8 ++++---- .../engine/archetypes/SimpleArchetypeProvider.kt | 10 +++++----- gradle/libs.versions.toml | 1 + 11 files changed, 38 insertions(+), 41 deletions(-) diff --git a/addons/geary-prefabs/build.gradle.kts b/addons/geary-prefabs/build.gradle.kts index f987d063..bdfd4faa 100644 --- a/addons/geary-prefabs/build.gradle.kts +++ b/addons/geary-prefabs/build.gradle.kts @@ -5,9 +5,6 @@ plugins { } kotlin { - targets { - - } sourceSets { val commonMain by getting { dependencies { diff --git a/build.gradle.kts b/build.gradle.kts index 9538f380..5d1e1661 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,6 +23,7 @@ allprojects { pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") { kotlin { jvm { + withJava() testRuns["test"].executionTask.configure { useJUnitPlatform() } diff --git a/geary-benchmarks/build.gradle.kts b/geary-benchmarks/build.gradle.kts index 5668d59b..e9ba322b 100644 --- a/geary-benchmarks/build.gradle.kts +++ b/geary-benchmarks/build.gradle.kts @@ -4,7 +4,7 @@ import org.jetbrains.kotlin.allopen.gradle.AllOpenExtension plugins { id(idofrontLibs.plugins.mia.kotlin.jvm.get().pluginId) id("org.jetbrains.kotlinx.benchmark") version "0.4.9" - kotlin("plugin.allopen") version "1.9.10" + kotlin("plugin.allopen") version idofrontLibs.versions.kotlin.get() } configure { diff --git a/geary-core/build.gradle.kts b/geary-core/build.gradle.kts index 9bd29693..98d96a93 100644 --- a/geary-core/build.gradle.kts +++ b/geary-core/build.gradle.kts @@ -4,17 +4,11 @@ plugins { alias(idofrontLibs.plugins.kotlinx.serialization) } -buildscript { - dependencies { - classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${libs.versions.atomicfu.get()}") - } -} - kotlin { sourceSets { val commonMain by getting { dependencies { - implementation(libs.atomicfu) + implementation(libs.stately.concurrency) implementation(libs.androidx.collection) implementation(idofrontLibs.kotlin.reflect) diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/EntityStack.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/EntityStack.kt index 02410f42..d2466551 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/EntityStack.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/EntityStack.kt @@ -2,12 +2,15 @@ package com.mineinabyss.geary.datatypes import com.mineinabyss.geary.helpers.toGeary -class EntityStack(private val stack: ArrayDeque = ArrayDeque()) { +class EntityStack( + @PublishedApi + internal val stack: ArrayDeque = ArrayDeque() +) { fun push(entity: Entity) { stack.add(entity.id.toLong()) } - fun pop(): Entity? = - if (stack.isEmpty()) null + inline fun popOrElse(orElse: () -> Entity): Entity = + if (stack.isEmpty()) orElse() else stack.removeFirst().toGeary() } diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/maps/SynchronizedTypeMap.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/maps/SynchronizedTypeMap.kt index cec89e4b..f62e15c6 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/maps/SynchronizedTypeMap.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/datatypes/maps/SynchronizedTypeMap.kt @@ -1,20 +1,21 @@ package com.mineinabyss.geary.datatypes.maps +import co.touchlab.stately.concurrency.Synchronizable +import co.touchlab.stately.concurrency.synchronize import com.mineinabyss.geary.datatypes.Entity import com.mineinabyss.geary.engine.archetypes.Archetype -import kotlinx.atomicfu.locks.SynchronizedObject -import kotlinx.atomicfu.locks.synchronized class SynchronizedArrayTypeMap : ArrayTypeMap() { - private val lock = SynchronizedObject() + private val lock = Synchronizable() override fun getArchAndRow(entity: Entity): ULong { - return synchronized(lock) { super.getArchAndRow(entity) } + return lock.synchronize { super.getArchAndRow(entity) } } + override fun set(entity: Entity, archetype: Archetype, row: Int) { - synchronized(lock) { super.set(entity, archetype, row) } + lock.synchronize { super.set(entity, archetype, row) } } - override fun remove(entity: Entity) = synchronized(lock) { super.remove(entity) } - override fun contains(entity: Entity): Boolean = synchronized(lock) { super.contains(entity) } + override fun remove(entity: Entity) = lock.synchronize { super.remove(entity) } + override fun contains(entity: Entity): Boolean = lock.synchronize { super.contains(entity) } } diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt index 7165843a..32fff305 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ArchetypeQueryManager.kt @@ -1,5 +1,7 @@ package com.mineinabyss.geary.engine.archetypes +import co.touchlab.stately.concurrency.Synchronizable +import co.touchlab.stately.concurrency.synchronize import com.mineinabyss.geary.datatypes.Entity import com.mineinabyss.geary.datatypes.family.Family import com.mineinabyss.geary.datatypes.maps.Family2ObjectArrayMap @@ -8,8 +10,6 @@ import com.mineinabyss.geary.helpers.contains import com.mineinabyss.geary.helpers.fastForEach import com.mineinabyss.geary.systems.query.CachedQuery import com.mineinabyss.geary.systems.query.Query -import kotlinx.atomicfu.locks.SynchronizedObject -import kotlinx.atomicfu.locks.synchronized class ArchetypeQueryManager : QueryManager { private val queries = mutableListOf>() @@ -19,7 +19,7 @@ class ArchetypeQueryManager : QueryManager { setIndex = { it, index -> it.id = index } ) - private val archetypeRegistryLock = SynchronizedObject() + private val archetypeRegistryLock = Synchronizable() val archetypeCount get() = archetypes.elements.size @@ -32,13 +32,13 @@ class ArchetypeQueryManager : QueryManager { return queryRunner } - internal fun registerArchetype(archetype: Archetype) = synchronized(archetypeRegistryLock) { + internal fun registerArchetype(archetype: Archetype) = archetypeRegistryLock.synchronize { archetypes.add(archetype, archetype.type) val matched = queries.filter { archetype.type in it.family } matched.fastForEach { it.matchedArchetypes += archetype } } - internal fun unregisterArchetype(archetype: Archetype) = synchronized(archetypeRegistryLock) { + internal fun unregisterArchetype(archetype: Archetype) = archetypeRegistryLock.synchronize { archetypes.remove(archetype) val matched = queries.filter { archetype.type in it.family } matched.fastForEach { it.matchedArchetypes -= archetype } diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ComponentAsEntityProvider.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ComponentAsEntityProvider.kt index a173d9f0..670819a6 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ComponentAsEntityProvider.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/ComponentAsEntityProvider.kt @@ -1,11 +1,11 @@ package com.mineinabyss.geary.engine.archetypes +import co.touchlab.stately.concurrency.Synchronizable +import co.touchlab.stately.concurrency.synchronize import com.mineinabyss.geary.components.ComponentInfo import com.mineinabyss.geary.datatypes.ComponentId import com.mineinabyss.geary.engine.ComponentProvider import com.mineinabyss.geary.modules.geary -import kotlinx.atomicfu.locks.SynchronizedObject -import kotlinx.atomicfu.locks.synchronized import kotlin.reflect.KClassifier class ComponentAsEntityProvider : ComponentProvider { @@ -13,7 +13,7 @@ class ComponentAsEntityProvider : ComponentProvider { private val logger get() = geary.logger private val classToComponentMap = mutableMapOf() - private val classToComponentMapLock = SynchronizedObject() + private val classToComponentMapLock = Synchronizable() internal fun createComponentInfo() { logger.v("Registering ComponentInfo component") @@ -24,11 +24,11 @@ class ComponentAsEntityProvider : ComponentProvider { } override fun getOrRegisterComponentIdForClass(kClass: KClassifier): ComponentId = - synchronized(classToComponentMapLock) { + classToComponentMapLock.synchronize { val id = classToComponentMap.getOrElse(kClass) { - return registerComponentIdForClass(kClass) + return@synchronize registerComponentIdForClass(kClass) } - return id.toULong() + return@synchronize id.toULong() } private fun registerComponentIdForClass(kClass: KClassifier): ComponentId { diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt index 5bd3d76d..3cd546e4 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/EntityByArchetypeProvider.kt @@ -1,5 +1,6 @@ package com.mineinabyss.geary.engine.archetypes +import co.touchlab.stately.concurrency.AtomicLong import com.mineinabyss.geary.datatypes.Entity import com.mineinabyss.geary.datatypes.EntityStack import com.mineinabyss.geary.datatypes.EntityType @@ -9,7 +10,6 @@ import com.mineinabyss.geary.engine.EntityProvider import com.mineinabyss.geary.helpers.* import com.mineinabyss.geary.modules.geary import com.mineinabyss.geary.observers.events.OnEntityRemoved -import kotlinx.atomicfu.atomic class EntityByArchetypeProvider( private val reuseIDsAfterRemoval: Boolean = true, @@ -20,12 +20,12 @@ class EntityByArchetypeProvider( private lateinit var root: Archetype private val removedEntities: EntityStack = EntityStack() - private val currId = atomic(0L) + private val currId = AtomicLong(0L) override fun create(): GearyEntity { val entity: GearyEntity = if (reuseIDsAfterRemoval) { - removedEntities.pop() ?: currId.getAndIncrement().toGeary() - } else currId.getAndIncrement().toGeary() + removedEntities.popOrElse { (currId.incrementAndGet() - 1).toGeary() } + } else (currId.incrementAndGet() - 1).toGeary() createRecord(entity) return entity diff --git a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/SimpleArchetypeProvider.kt b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/SimpleArchetypeProvider.kt index 6b277107..28960e6a 100644 --- a/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/SimpleArchetypeProvider.kt +++ b/geary-core/src/commonMain/kotlin/com/mineinabyss/geary/engine/archetypes/SimpleArchetypeProvider.kt @@ -2,11 +2,11 @@ package com.mineinabyss.geary.engine.archetypes import androidx.collection.getOrElse import androidx.collection.set +import co.touchlab.stately.concurrency.Synchronizable +import co.touchlab.stately.concurrency.synchronize import com.mineinabyss.geary.datatypes.ComponentId import com.mineinabyss.geary.datatypes.EntityType import com.mineinabyss.geary.modules.archetypes -import kotlinx.atomicfu.locks.SynchronizedObject -import kotlinx.atomicfu.locks.synchronized class SimpleArchetypeProvider : ArchetypeProvider { private val queryManager: ArchetypeQueryManager get() = archetypes.queryManager @@ -17,7 +17,7 @@ class SimpleArchetypeProvider : ArchetypeProvider { } } - private val archetypeWriteLock = SynchronizedObject() + private val archetypeWriteLock = Synchronizable() private fun createArchetype(prevNode: Archetype, componentEdge: ComponentId): Archetype { @@ -29,11 +29,11 @@ class SimpleArchetypeProvider : ArchetypeProvider { return arc } - override fun getArchetype(entityType: EntityType): Archetype = synchronized(archetypeWriteLock) { + override fun getArchetype(entityType: EntityType): Archetype = archetypeWriteLock.synchronize { var node = rootArchetype entityType.forEach { compId -> node = node.componentAddEdges.getOrElse(compId.toLong()) { createArchetype(node, compId) } } - return node + return@synchronize node } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ed47de1b..0bfbcf83 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,3 +9,4 @@ roaringbitmap = "org.roaringbitmap:RoaringBitmap:0.9.32" bitvector = "net.onedaybeard.bitvector:bitvector-js:0.1.4" kermit = "co.touchlab:kermit:1.2.2" androidx-collection = "androidx.collection:collection:1.4.0" +stately-concurrency = "co.touchlab:stately-concurrency:2.0.7"