Created
January 8, 2019 13:54
-
-
Save rock3r/6fc350397863efd59060b024d963e15a to your computer and use it in GitHub Desktop.
A cacheable property in Kotlin — basically, a variant of Lazy that can be invalidated and will be reloaded on the next access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.seebrock3r.util | |
import me.seebrock3r.util.CacheableProperty.CachedValue.* | |
import kotlin.properties.* | |
import kotlin.reflect.* | |
import kotlin.reflect.jvm.* | |
fun <T> cache(producer: () -> T): CacheableProperty<T> = CacheableProperty(producer) | |
class CacheableProperty<out T>(val producer: () -> T) : ReadOnlyProperty<Any, T> { | |
private var value: CachedValue<T> = CachedValue.Nothing | |
override fun getValue(thisRef: Any, property: KProperty<*>): T = | |
when (value) { | |
is CachedValue.Nothing -> producer().also { value = CachedValue.Something(it) } | |
is CachedValue.Something<T> -> (value as Something<T>).value | |
} | |
fun invalidate() { | |
value = CachedValue.Nothing | |
} | |
private sealed class CachedValue<out T> { | |
class Something<out T>(val value: T) : CachedValue<T>() | |
object Nothing : CachedValue<kotlin.Nothing>() | |
} | |
} | |
fun KProperty0<*>.invalidateCacheableProperty() { | |
val wasAccessible = isAccessible | |
isAccessible = true | |
if (getDelegate() !is CacheableProperty<*>) { | |
throw UnsupportedOperationException("Only CacheableProperty supports invalidation") | |
} | |
(getDelegate() as CacheableProperty<*>).invalidate() | |
isAccessible = wasAccessible | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal class UsageExample(private val path: Path) { | |
// Silly example, you could not do all this but whatevs | |
private val _lines by lazy { Files.readAllLines(path).toMutableList() } | |
val lines: List<String> | |
get() = _lines.toList() | |
val linesCount | |
get() = _lines.size | |
val contents by cache { _lines.joinToString(separator = "\n") } | |
fun addLine(lineText: String, insertPosition: Int = linesCount) { | |
_lines.add(insertPosition, lineText) | |
invalidateCacheBecauseContentsChanged() | |
} | |
private fun invalidateCacheBecauseContentsChanged() { | |
::contents.invalidateCacheableProperty() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment