AtomicLazy.kt 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. /*
  2. * Copyright 2019-2021 Mamoe Technologies and contributors.
  3. *
  4. * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  5. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  6. *
  7. * https://github.com/mamoe/mirai/blob/master/LICENSE
  8. */
  9. package net.mamoe.mirai.utils
  10. import kotlinx.atomicfu.atomic
  11. import kotlin.properties.ReadWriteProperty
  12. import kotlin.reflect.KProperty
  13. private val UNINITIALIZED: Any? = Symbol("UNINITIALIZED")
  14. /**
  15. * - [initializer] is supported to be called at most once, however multiple invocations may happen if executed by multiple coroutines in single thread.
  16. * - [ReadWriteProperty.setValue] prevails on competition with [initializer].
  17. */
  18. public fun <T> lateinitMutableProperty(initializer: () -> T): ReadWriteProperty<Any?, T> =
  19. LateinitMutableProperty(initializer)
  20. private class LateinitMutableProperty<T>(
  21. initializer: () -> T
  22. ) : ReadWriteProperty<Any?, T> {
  23. private val value = atomic(UNINITIALIZED)
  24. private var initializer: (() -> T)? = initializer
  25. @Suppress("UNCHECKED_CAST")
  26. override fun getValue(thisRef: Any?, property: KProperty<*>): T {
  27. return when (val v = this.value.value) {
  28. UNINITIALIZED -> synchronized(this) {
  29. val initializer = initializer
  30. if (initializer != null && this.value.value === UNINITIALIZED) {
  31. val value = initializer()
  32. this.value.compareAndSet(UNINITIALIZED, value) // setValue prevails
  33. this.initializer = null
  34. value
  35. } else v as T
  36. }
  37. else -> v as T
  38. }
  39. }
  40. override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
  41. this.value.value = value
  42. }
  43. }