Created
August 8, 2017 08:39
-
-
Save justasm/2dd30ff9a699fd33b13f53d95e6c0ea4 to your computer and use it in GitHub Desktop.
Kotlin Lazy for mutable values
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
@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