[K/N] Implement Lazy for new mm
This commit is contained in:
@@ -5,9 +5,10 @@
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.native.concurrent.FreezeAwareLazyImpl
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.internal.FixmeConcurrency
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.native.isExperimentalMM
|
||||
|
||||
/**
|
||||
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
|
||||
@@ -18,7 +19,13 @@ import kotlin.reflect.KProperty
|
||||
* Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
|
||||
* the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
|
||||
*/
|
||||
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = FreezeAwareLazyImpl(initializer)
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
public actual fun <T> lazy(initializer: () -> T): Lazy<T> =
|
||||
if (isExperimentalMM())
|
||||
SynchronizedLazyImpl(initializer)
|
||||
else
|
||||
FreezeAwareLazyImpl(initializer)
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
|
||||
@@ -31,10 +38,11 @@ public actual fun <T> lazy(initializer: () -> T): Lazy<T> = FreezeAwareLazyImpl(
|
||||
* Also this behavior can be changed in the future.
|
||||
*/
|
||||
@FixmeConcurrency
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
|
||||
when (mode) {
|
||||
LazyThreadSafetyMode.SYNCHRONIZED -> throw UnsupportedOperationException()
|
||||
LazyThreadSafetyMode.PUBLICATION -> FreezeAwareLazyImpl(initializer)
|
||||
LazyThreadSafetyMode.SYNCHRONIZED -> if (isExperimentalMM()) SynchronizedLazyImpl(initializer) else throw UnsupportedOperationException()
|
||||
LazyThreadSafetyMode.PUBLICATION -> if (isExperimentalMM()) SafePublicationLazyImpl(initializer) else FreezeAwareLazyImpl(initializer)
|
||||
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
|
||||
}
|
||||
|
||||
|
||||
@@ -121,3 +121,78 @@ internal class AtomicLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
|
||||
* such as object signletons, or in cases where it's guaranteed not to have cyclical garbage.
|
||||
*/
|
||||
public fun <T> atomicLazy(initializer: () -> T): Lazy<T> = AtomicLazyImpl(initializer)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal class SynchronizedLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
|
||||
private var initializer = FreezableAtomicReference<(() -> T)?>(initializer)
|
||||
private var valueRef = FreezableAtomicReference<Any?>(UNINITIALIZED)
|
||||
private val lock = Lock()
|
||||
|
||||
override val value: T
|
||||
get() {
|
||||
val _v1 = valueRef.value
|
||||
if (_v1 !== UNINITIALIZED) {
|
||||
return _v1 as T
|
||||
}
|
||||
|
||||
return locked(lock) {
|
||||
val _v2 = valueRef.value
|
||||
if (_v2 === UNINITIALIZED) {
|
||||
val wasFrozen = this.isFrozen
|
||||
val typedValue = initializer.value!!()
|
||||
if (this.isFrozen) {
|
||||
if (!wasFrozen) {
|
||||
throw InvalidMutabilityException("Frozen during lazy computation")
|
||||
}
|
||||
typedValue.freeze()
|
||||
}
|
||||
valueRef.value = typedValue
|
||||
initializer.value = null
|
||||
typedValue
|
||||
} else {
|
||||
_v2 as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInitialized() = valueRef.value !== UNINITIALIZED
|
||||
|
||||
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
|
||||
}
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
|
||||
private var initializer = FreezableAtomicReference<(() -> T)?>(initializer)
|
||||
private var valueRef = FreezableAtomicReference<Any?>(UNINITIALIZED)
|
||||
|
||||
override val value: T
|
||||
get() {
|
||||
val value = valueRef.value
|
||||
if (value !== UNINITIALIZED) {
|
||||
return value as T
|
||||
}
|
||||
|
||||
val initializerValue = initializer.value
|
||||
// if we see null in initializer here, it means that the value is already set by another thread
|
||||
if (initializerValue != null) {
|
||||
val wasFrozen = this.isFrozen
|
||||
val newValue = initializerValue()
|
||||
if (this.isFrozen) {
|
||||
if (!wasFrozen) {
|
||||
throw InvalidMutabilityException("Frozen during lazy computation")
|
||||
}
|
||||
newValue.freeze()
|
||||
}
|
||||
if (valueRef.compareAndSet(UNINITIALIZED, newValue)) {
|
||||
initializer.value = null
|
||||
return newValue
|
||||
}
|
||||
}
|
||||
return valueRef.value as T
|
||||
}
|
||||
|
||||
override fun isInitialized(): Boolean = valueRef.value !== UNINITIALIZED
|
||||
|
||||
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
|
||||
}
|
||||
Reference in New Issue
Block a user