From a30bb945d262e18e634cd17d486508911b297ac5 Mon Sep 17 00:00:00 2001 From: Kyle Corry Date: Thu, 28 Mar 2024 19:05:09 -0400 Subject: [PATCH] Add equality change detector --- .../kylecorry/luna/equality/ChangeDetector.kt | 6 +++ .../luna/equality/EqualityChangeDetector.kt | 44 +++++++++++++++++++ .../{hash => equality}/HashChangeDetector.kt | 8 ++-- .../luna/{hash => equality}/HashUtils.kt | 2 +- .../kotlin/com/kylecorry/luna/hooks/Effect.kt | 4 +- .../com/kylecorry/luna/hooks/MemoizedValue.kt | 4 +- 6 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/com/kylecorry/luna/equality/ChangeDetector.kt create mode 100644 src/main/kotlin/com/kylecorry/luna/equality/EqualityChangeDetector.kt rename src/main/kotlin/com/kylecorry/luna/{hash => equality}/HashChangeDetector.kt (82%) rename src/main/kotlin/com/kylecorry/luna/{hash => equality}/HashUtils.kt (85%) diff --git a/src/main/kotlin/com/kylecorry/luna/equality/ChangeDetector.kt b/src/main/kotlin/com/kylecorry/luna/equality/ChangeDetector.kt new file mode 100644 index 0000000..6665133 --- /dev/null +++ b/src/main/kotlin/com/kylecorry/luna/equality/ChangeDetector.kt @@ -0,0 +1,6 @@ +package com.kylecorry.luna.equality + +interface ChangeDetector { + fun hasChanges(values: Array): Boolean + fun reset() +} \ No newline at end of file diff --git a/src/main/kotlin/com/kylecorry/luna/equality/EqualityChangeDetector.kt b/src/main/kotlin/com/kylecorry/luna/equality/EqualityChangeDetector.kt new file mode 100644 index 0000000..db98ff2 --- /dev/null +++ b/src/main/kotlin/com/kylecorry/luna/equality/EqualityChangeDetector.kt @@ -0,0 +1,44 @@ +package com.kylecorry.luna.equality + +class EqualityChangeDetector : ChangeDetector { + + private val lock = Any() + private var cachedValues: MutableList? = null + + override fun hasChanges(values: Array): Boolean = synchronized(lock) { + var changed = false + + val cached = if (cachedValues == null) { + cachedValues = mutableListOf() + changed = true + cachedValues + } else { + cachedValues + }!! + + if (cached.size != values.size) { + values.forEachIndexed { index, value -> + if (index >= cached.size) { + cached.add(value) + } else { + cached[index] = value + } + } + changed = true + } else { + values.forEachIndexed { index, value -> + if (value != cached[index]) { + cached[index] = value + changed = true + } + } + } + + return changed + } + + override fun reset() = synchronized(lock) { + cachedValues = null + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/kylecorry/luna/hash/HashChangeDetector.kt b/src/main/kotlin/com/kylecorry/luna/equality/HashChangeDetector.kt similarity index 82% rename from src/main/kotlin/com/kylecorry/luna/hash/HashChangeDetector.kt rename to src/main/kotlin/com/kylecorry/luna/equality/HashChangeDetector.kt index e8136b5..24b77c7 100644 --- a/src/main/kotlin/com/kylecorry/luna/hash/HashChangeDetector.kt +++ b/src/main/kotlin/com/kylecorry/luna/equality/HashChangeDetector.kt @@ -1,11 +1,11 @@ -package com.kylecorry.luna.hash +package com.kylecorry.luna.equality -class HashChangeDetector { +class HashChangeDetector: ChangeDetector { private val lock = Any() private var cachedHashes: MutableList? = null - fun hasChanges(values: Array): Boolean = synchronized(lock) { + override fun hasChanges(values: Array): Boolean = synchronized(lock) { var changed = false val cached = if (cachedHashes == null) { @@ -38,7 +38,7 @@ class HashChangeDetector { return changed } - fun reset() = synchronized(lock) { + override fun reset() = synchronized(lock) { cachedHashes = null } diff --git a/src/main/kotlin/com/kylecorry/luna/hash/HashUtils.kt b/src/main/kotlin/com/kylecorry/luna/equality/HashUtils.kt similarity index 85% rename from src/main/kotlin/com/kylecorry/luna/hash/HashUtils.kt rename to src/main/kotlin/com/kylecorry/luna/equality/HashUtils.kt index 9ebadfb..aafc351 100644 --- a/src/main/kotlin/com/kylecorry/luna/hash/HashUtils.kt +++ b/src/main/kotlin/com/kylecorry/luna/equality/HashUtils.kt @@ -1,4 +1,4 @@ -package com.kylecorry.luna.hash +package com.kylecorry.luna.equality object HashUtils { diff --git a/src/main/kotlin/com/kylecorry/luna/hooks/Effect.kt b/src/main/kotlin/com/kylecorry/luna/hooks/Effect.kt index e83ddd9..8dbec45 100644 --- a/src/main/kotlin/com/kylecorry/luna/hooks/Effect.kt +++ b/src/main/kotlin/com/kylecorry/luna/hooks/Effect.kt @@ -1,6 +1,6 @@ package com.kylecorry.luna.hooks -import com.kylecorry.luna.hash.HashChangeDetector +import com.kylecorry.luna.equality.EqualityChangeDetector /** * An effect that runs an action if the state has changed (similar to the effect hook in React) @@ -8,7 +8,7 @@ import com.kylecorry.luna.hash.HashChangeDetector class Effect { private val lock = Any() - private val changeDetector = HashChangeDetector() + private val changeDetector = EqualityChangeDetector() /** * Run an action if the values have changed diff --git a/src/main/kotlin/com/kylecorry/luna/hooks/MemoizedValue.kt b/src/main/kotlin/com/kylecorry/luna/hooks/MemoizedValue.kt index 4395bea..abab4ac 100644 --- a/src/main/kotlin/com/kylecorry/luna/hooks/MemoizedValue.kt +++ b/src/main/kotlin/com/kylecorry/luna/hooks/MemoizedValue.kt @@ -1,11 +1,11 @@ package com.kylecorry.luna.hooks -import com.kylecorry.luna.hash.HashChangeDetector +import com.kylecorry.luna.equality.EqualityChangeDetector class MemoizedValue { private var cachedValue: T? = null - private val changeDetector = HashChangeDetector() + private val changeDetector = EqualityChangeDetector() private val lock = Any() fun getOrPut(vararg dependencies: Any?, value: () -> T): T = synchronized(lock) {