Skip to content

Commit

Permalink
Fixes for orDefault and map accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
0ffz committed Feb 25, 2024
1 parent 9cf2748 commit 6202329
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ abstract class AccessorOperations {

/** Accesses a component, ensuring it is on the entity. */
protected inline fun <reified T : Any> QueriedEntity.get(): ComponentAccessor<T> {
return addAccessor { NonNullComponentAccessor(cacheAccessors, null, this, componentId<T>().withRole(HOLDS_DATA)) }
return addAccessor {
NonNullComponentAccessor(cacheAccessors, null, this, componentId<T>().withRole(HOLDS_DATA))
}
}

/** Accesses a data stored in a relation with kind [K] and target type [T], ensuring it is on the entity. */
Expand All @@ -26,6 +28,7 @@ abstract class AccessorOperations {
inline fun <T : Accessor> QueriedEntity.addAccessor(create: () -> T): T {
val accessor = create()
accessors.add(accessor)
if (accessor is ComponentAccessor<*>) cachingAccessors.add(accessor)
if (accessor.originalAccessor != null) accessors.remove(accessor.originalAccessor)
return accessor
}
Expand All @@ -51,7 +54,9 @@ abstract class AccessorOperations {
fun <T, U, A : ReadOnlyAccessor<T>> A.map(mapping: (T) -> U): ReadOnlyAccessor<U> {
return queriedEntity.addAccessor {
when (this) {
is FamilyMatching -> object : ReadOnlyAccessor<U> by MappedAccessor(this, mapping), FamilyMatching by this {}
is FamilyMatching -> object : ReadOnlyAccessor<U> by MappedAccessor(this, mapping),
FamilyMatching by this {}

else -> MappedAccessor(this, mapping)
}
}
Expand Down Expand Up @@ -80,7 +85,14 @@ abstract class AccessorOperations {

/** @see getRelations */
protected inline fun <reified K : Component?, reified T : Component?> QueriedEntity.getRelationsWithData(): RelationsWithDataAccessor<K, T> {
return addAccessor { RelationsWithDataAccessor(null, this, componentIdWithNullable<K>(), componentIdWithNullable<T>()) }
return addAccessor {
RelationsWithDataAccessor(
null,
this,
componentIdWithNullable<K>(),
componentIdWithNullable<T>()
)
}
}

protected operator fun QueriedEntity.invoke(init: MutableFamily.Selector.And.() -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mineinabyss.geary.systems.accessors

import com.mineinabyss.geary.engine.archetypes.Archetype
import com.mineinabyss.geary.systems.query.CachedQueryRunner
import com.mineinabyss.geary.systems.query.QueriedEntity
import com.mineinabyss.geary.systems.query.Query
import kotlin.properties.ReadOnlyProperty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ abstract class ComponentAccessor<T>(
protected var cachedIndex = -1
protected var cachedDataArray: MutableList<T> = mutableListOf()

@PublishedApi
internal fun updateCache(archetype: Archetype) {
fun updateCache(archetype: Archetype) {
cachedIndex = archetype.indexOf(id)
if (cachedIndex != -1) cachedDataArray = archetype.componentData[cachedIndex] as MutableList<T>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mineinabyss.geary.systems.accessors.type

import com.mineinabyss.geary.engine.archetypes.Archetype
import com.mineinabyss.geary.systems.accessors.AccessorOperations
import com.mineinabyss.geary.systems.accessors.ReadOnlyAccessor
import com.mineinabyss.geary.systems.query.QueriedEntity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@ import com.mineinabyss.geary.systems.accessors.type.ComponentAccessor
class CachedQueryRunner<T : Query> internal constructor(val query: T) {
val matchedArchetypes: MutableList<Archetype> = mutableListOf()
val family = query.buildFamily()
val accessors = query.accessors.toTypedArray().filterIsInstance<ComponentAccessor<*>>()

inline fun <R> toList(crossinline map: T.() -> R): List<R> {
val list = mutableListOf<R>()
forEach { list.add(this.map()) }
return list
}
val cachingAccessors = query.cachingAccessors.toTypedArray()

/**
* Quickly iterates over all matched entities, running [run] for each.
Expand All @@ -26,7 +20,7 @@ class CachedQueryRunner<T : Query> internal constructor(val query: T) {
val matched = matchedArchetypes
var n = 0
val size = matched.size // Get size ahead of time to avoid rerunning on entities that end up in new archetypes
val accessors = accessors
val accessors = cachingAccessors
while (n < size) {
val archetype = matched[n]
archetype.isIterating = true
Expand All @@ -47,9 +41,7 @@ class CachedQueryRunner<T : Query> internal constructor(val query: T) {

inline fun <R> map(crossinline run: T.() -> R): List<R> {
val deferred = mutableListOf<R>()
forEach {
deferred.add(run())
}
forEach { deferred.add(run()) }
return deferred
}

Expand All @@ -62,10 +54,17 @@ class CachedQueryRunner<T : Query> internal constructor(val query: T) {
inline fun <R> mapWithEntity(crossinline run: T.() -> R): List<Deferred<R>> {
val deferred = mutableListOf<Deferred<R>>()
forEach {
deferred.add(Deferred(run(), archetype.getEntity(row)))
deferred.add(Deferred(run(), unsafeEntity))
}
return deferred
}

@OptIn(UnsafeAccessors::class)
fun entities(): List<GearyEntity> {
val entities = mutableListOf<GearyEntity>()
forEach { entities.add(unsafeEntity) }
return entities
}
}

inline fun <R> List<CachedQueryRunner.Deferred<R>>.execOnFinish(run: (data: R, entity: GearyEntity) -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.mineinabyss.geary.modules.archetypes
import com.mineinabyss.geary.systems.accessors.Accessor
import com.mineinabyss.geary.systems.accessors.AccessorOperations
import com.mineinabyss.geary.systems.accessors.FamilyMatching
import com.mineinabyss.geary.systems.accessors.type.ComponentAccessor

open class EventQueriedEntity : QueriedEntity(cacheAccessors = false)
open class QueriedEntity(
Expand All @@ -23,6 +24,9 @@ open class QueriedEntity(
@PublishedApi
internal val accessors: MutableSet<Accessor> = mutableSetOf()

@PublishedApi
internal val cachingAccessors: MutableSet<ComponentAccessor<*>> = mutableSetOf()

fun buildFamily(): Family.Selector.And = family {
accessors
.filterIsInstance<FamilyMatching>()
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.mineinabyss.geary.systems.accessors

import com.mineinabyss.geary.helpers.entity
import com.mineinabyss.geary.helpers.tests.GearyTest
import com.mineinabyss.geary.modules.geary
import com.mineinabyss.geary.systems.builders.cachedQuery
import com.mineinabyss.geary.systems.query.Query
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

internal class MappedAccessorTests : GearyTest() {
private class Marker

private fun mappedQuery() = geary.cachedQuery(object : Query() {
val mapped by get<Int>().map { it.toString() }
})

private fun defaultingQuery() = geary.cachedQuery(object : Query() {
val default by get<String>().orDefault { "empty!" }
override fun ensure() = this { has<Marker>() }
})

@Test
fun `should correctly get mapped accessors`() {
entity {
set(1)
}
mappedQuery().forEach {
mapped shouldBe "1"
}
}

@Test
fun `should correctly get default accessors`() {
entity {
set("Hello")
add<Marker>()
}
entity {
add<Marker>()
}
defaultingQuery().map { default }.shouldContainExactly("Hello", "empty!")
}
}

0 comments on commit 6202329

Please sign in to comment.