Skip to content

Instantly share code, notes, and snippets.

@justasm
Created August 8, 2017 08:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justasm/2dd30ff9a699fd33b13f53d95e6c0ea4 to your computer and use it in GitHub Desktop.
Save justasm/2dd30ff9a699fd33b13f53d95e6c0ea4 to your computer and use it in GitHub Desktop.
Kotlin Lazy for mutable values
@file:Suppress("RedundantVisibilityModifier", "NOTHING_TO_INLINE")
import kotlin.reflect.KProperty
public interface LazyMutable<T> {
public var value: T
public fun isInitialized(): Boolean
}
public inline operator fun <T> LazyMutable<T>.getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public inline operator fun <T> LazyMutable<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
public fun <T> lazyMutable(initializer: () -> T): LazyMutable<T> = SynchronizedLazyMutableImpl(initializer)
public fun <T> lazyMutable(initializer: () -> T, onChange: (newValue: T) -> Unit): LazyMutable<T> = SynchronizedLazyMutableImpl(initializer, onChange)
private object UNINITIALIZED_VALUE
private class SynchronizedLazyMutableImpl<T>(initializer: () -> T,
private val onChange: ((newValue: T) -> Unit)? = null,
lock: Any? = null) : LazyMutable<T> {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override var value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
set(value) {
synchronized(lock) {
_value = value
}
onChange?.invoke(value)
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment