Skip to content

Instantly share code, notes, and snippets.

@LouisCAD
Created May 1, 2020 21:31
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 LouisCAD/e59fe365ad29225c6da9dfc2fc00f4d6 to your computer and use it in GitHub Desktop.
Save LouisCAD/e59fe365ad29225c6da9dfc2fc00f4d6 to your computer and use it in GitHub Desktop.
import java.io.Serializable
import kotlin.reflect.KProperty
interface MutableLazy<T> : Lazy<T> {
override var value: T
}
fun <T> mutableLazyOf(value: T): MutableLazy<T> = InitializedLazyImpl(value)
fun <T> mutableLazy(initializer: () -> T): MutableLazy<T> = SynchronizedLazyImpl(initializer)
fun <T> mutableLazy(mode: LazyThreadSafetyMode, initializer: () -> T): MutableLazy<T> =
when (mode) {
LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
LazyThreadSafetyMode.PUBLICATION -> TODO("PUBLICATION mode not supported for MutableLazy yet")
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
}
fun <T> mutableLazy(lock: Any?, initializer: () -> T): MutableLazy<T> = SynchronizedLazyImpl(initializer, lock)
@Suppress("NOTHING_TO_INLINE")
inline operator fun <T> MutableLazy<T>.setValue(thisRef: Any?, property: KProperty<*>, newVal: T) {
value = newVal
}
private val UNINITIALIZED_VALUE = Any()
private class SynchronizedLazyImpl<T>(initializer: () -> T, lock: Any? = null) : MutableLazy<T>, Serializable {
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) {
initializer = null
_value = value
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
// internal to be called from lazy in JS
internal class UnsafeLazyImpl<T>(initializer: () -> T) : MutableLazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
private var _value: Any? = UNINITIALIZED_VALUE
override var value: T
get() {
if (_value === UNINITIALIZED_VALUE) {
_value = initializer!!()
initializer = null
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
set(value) {
initializer = null
_value = value
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
private class InitializedLazyImpl<T>(override var value: T) : MutableLazy<T> {
override fun isInitialized(): Boolean = true
override fun toString(): String = value.toString()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment