From 0c1cc78ee415e9c358cd414dcd748ff891ba8784 Mon Sep 17 00:00:00 2001 From: lisonge Date: Wed, 3 Jul 2024 17:38:05 +0800 Subject: [PATCH] perf: cache, lazy invoke --- .../main/kotlin/li/songe/gkd/data/ResolvedRule.kt | 15 ++++++++------- app/src/main/kotlin/li/songe/gkd/service/AbExt.kt | 7 ++++--- .../li/songe/selector/MultiplatformTransform.kt | 2 +- .../kotlin/li/songe/selector/Selector.kt | 7 ++----- .../kotlin/li/songe/selector/Transform.kt | 2 +- .../kotlin/li/songe/selector/ValueExpression.kt | 7 ++++--- .../commonMain/kotlin/li/songe/selector/util.kt | 7 +++++++ 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/app/src/main/kotlin/li/songe/gkd/data/ResolvedRule.kt b/app/src/main/kotlin/li/songe/gkd/data/ResolvedRule.kt index 7c589813e..1bfb73c0b 100644 --- a/app/src/main/kotlin/li/songe/gkd/data/ResolvedRule.kt +++ b/app/src/main/kotlin/li/songe/gkd/data/ResolvedRule.kt @@ -4,7 +4,7 @@ import android.accessibilityservice.AccessibilityService import android.view.accessibility.AccessibilityNodeInfo import kotlinx.coroutines.Job import li.songe.gkd.service.createCacheTransform -import li.songe.gkd.service.createTransform +import li.songe.gkd.service.createNoCacheTransform import li.songe.gkd.service.lastTriggerRule import li.songe.gkd.service.lastTriggerTime import li.songe.gkd.service.querySelector @@ -130,8 +130,8 @@ sealed class ResolvedRule( else -> true } - private val canCacheIndex = (matches + excludeMatches).any { s -> s.useCache } - private val transform = if (canCacheIndex) defaultCacheTransform.transform else defaultTransform + private val useCache = (matches + excludeMatches).any { s -> s.useCache } + private val transform = if (useCache) defaultCacheTransform else defaultTransform fun query( nodeInfo: AccessibilityNodeInfo?, @@ -141,24 +141,25 @@ sealed class ResolvedRule( var target: AccessibilityNodeInfo? = null if (anyMatches.isNotEmpty()) { for (selector in anyMatches) { - target = nodeInfo.querySelector(selector, quickFind, transform) + target = nodeInfo.querySelector(selector, quickFind, transform.transform) ?: break } if (target == null) return null } for (selector in matches) { - target = nodeInfo.querySelector(selector, quickFind, transform) + target = nodeInfo.querySelector(selector, quickFind, transform.transform) ?: return null } for (selector in excludeMatches) { nodeInfo.querySelector( selector, quickFind, - transform + transform.transform )?.let { return null } } return target } finally { + defaultTransform.cache.clear() defaultCacheTransform.cache.clear() } } @@ -247,7 +248,7 @@ fun getFixActivityIds( } } -private val defaultTransform = createTransform() +private val defaultTransform = createNoCacheTransform() private val defaultCacheTransform = createCacheTransform() diff --git a/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt b/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt index 2bba504f2..df92e58d2 100644 --- a/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt +++ b/app/src/main/kotlin/li/songe/gkd/service/AbExt.kt @@ -493,14 +493,14 @@ fun createCacheTransform(): CacheTransform { return CacheTransform(transform, cache) } -private fun List.getIntOrNull(i: Int = 0): Int? { +private fun List.getIntOrNull(i: Int = 0): Int? { return getOrNull(i) as? Int ?: return null } -fun createTransform(): Transform { +fun createNoCacheTransform(): CacheTransform { val cache = NodeCache() val getNodeAttr = createGetNodeAttr(cache) - return Transform( + val transform = Transform( getAttr = { target, name -> when (target) { is AccessibilityNodeInfo -> getNodeAttr(target, name) @@ -569,4 +569,5 @@ fun createTransform(): Transform { } }, ) + return CacheTransform(transform, cache) } diff --git a/selector/src/commonMain/kotlin/li/songe/selector/MultiplatformTransform.kt b/selector/src/commonMain/kotlin/li/songe/selector/MultiplatformTransform.kt index 3d303ed6b..8ba587c3d 100644 --- a/selector/src/commonMain/kotlin/li/songe/selector/MultiplatformTransform.kt +++ b/selector/src/commonMain/kotlin/li/songe/selector/MultiplatformTransform.kt @@ -6,7 +6,7 @@ import kotlin.js.JsExport @Suppress("UNCHECKED_CAST", "UNUSED") class MultiplatformTransform( getAttr: (Any?, String) -> Any?, - getInvoke: (Any?, String, List) -> Any?, + getInvoke: (Any?, String, List) -> Any?, getName: (T) -> String?, getChildren: (T) -> Array, getParent: (T) -> T?, diff --git a/selector/src/commonMain/kotlin/li/songe/selector/Selector.kt b/selector/src/commonMain/kotlin/li/songe/selector/Selector.kt index be5a9567e..8eb1ea706 100644 --- a/selector/src/commonMain/kotlin/li/songe/selector/Selector.kt +++ b/selector/src/commonMain/kotlin/li/songe/selector/Selector.kt @@ -93,10 +93,7 @@ class Selector internal constructor( } val useCache = run { - if (connectKeys.contains(ConnectOperator.BeforeBrother.key)) { - return@run true - } - if (connectKeys.contains(ConnectOperator.AfterBrother.key)) { + if (connectKeys.isNotEmpty()) { return@run true } binaryExpressions.forEach { b -> @@ -139,7 +136,7 @@ class Selector internal constructor( } private val useCacheProperties by lazy { - arrayOf("index", "parent") + arrayOf("index", "parent", "depth") } private val useCacheMethods by lazy { arrayOf("getChild") diff --git a/selector/src/commonMain/kotlin/li/songe/selector/Transform.kt b/selector/src/commonMain/kotlin/li/songe/selector/Transform.kt index 6e2801afe..3fc4c1d33 100644 --- a/selector/src/commonMain/kotlin/li/songe/selector/Transform.kt +++ b/selector/src/commonMain/kotlin/li/songe/selector/Transform.kt @@ -3,7 +3,7 @@ package li.songe.selector @Suppress("UNUSED") class Transform( val getAttr: (Any?, String) -> Any?, - val getInvoke: (Any?, String, List) -> Any? = { _, _, _ -> null }, + val getInvoke: (Any?, String, List) -> Any? = { _, _, _ -> null }, val getName: (T) -> CharSequence?, val getChildren: (T) -> Sequence, val getParent: (T) -> T?, diff --git a/selector/src/commonMain/kotlin/li/songe/selector/ValueExpression.kt b/selector/src/commonMain/kotlin/li/songe/selector/ValueExpression.kt index a0ba0fbd2..ace308945 100644 --- a/selector/src/commonMain/kotlin/li/songe/selector/ValueExpression.kt +++ b/selector/src/commonMain/kotlin/li/songe/selector/ValueExpression.kt @@ -56,6 +56,7 @@ sealed class ValueExpression(open val value: Any?, open val type: String) : Posi override fun getAttr(node: T, transform: Transform): Any? { return when (callee) { is CallExpression -> { + // not support null } @@ -63,15 +64,15 @@ sealed class ValueExpression(open val value: Any?, open val type: String) : Posi transform.getInvoke( node, callee.value, - arguments.map { it.getAttr(node, transform) } + arguments.map { it.getAttr(node, transform).whenNull { return null } } ) } is MemberExpression -> { transform.getInvoke( - callee.object0.getAttr(node, transform), + callee.object0.getAttr(node, transform).whenNull { return null }, callee.property, - arguments.map { it.getAttr(node, transform) } + arguments.map { it.getAttr(node, transform).whenNull { return null } } ) } } diff --git a/selector/src/commonMain/kotlin/li/songe/selector/util.kt b/selector/src/commonMain/kotlin/li/songe/selector/util.kt index affbc500d..f1035f74f 100644 --- a/selector/src/commonMain/kotlin/li/songe/selector/util.kt +++ b/selector/src/commonMain/kotlin/li/songe/selector/util.kt @@ -63,6 +63,13 @@ internal fun optimizeMatchString(value: String): ((CharSequence) -> Boolean)? { return null } +internal inline fun T?.whenNull(block: () -> Nothing): T { + if (this == null) { + block() + } + return this +} + @JsExport class DefaultTypeInfo( val booleanType: TypeInfo,