Created
May 1, 2020 21:31
-
-
Save LouisCAD/e59fe365ad29225c6da9dfc2fc00f4d6 to your computer and use it in GitHub Desktop.
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
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