org.jetbrains.kotlin.util.ArrayMapOwner.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.util
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
@RequiresOptIn
annotation class Protected
abstract class AbstractArrayMapOwner : Iterable {
protected abstract val arrayMap: ArrayMap
protected abstract val typeRegistry: TypeRegistry
abstract class AbstractArrayMapAccessor(
protected val id: Int
) {
protected fun extractValue(thisRef: AbstractArrayMapOwner): T? {
@Suppress("UNCHECKED_CAST")
return thisRef.arrayMap[id] as T?
}
}
protected abstract fun registerComponent(keyQualifiedName: String, value: V)
protected fun registerComponent(tClass: KClass, value: V) {
registerComponent(tClass.qualifiedName!!, value)
}
final override fun iterator(): Iterator = arrayMap.iterator()
fun isEmpty(): Boolean = arrayMap.size == 0
fun isNotEmpty(): Boolean = arrayMap.size != 0
operator fun get(index: Int): V? = arrayMap[index]
}
class ArrayMapAccessor(
private val keyQualifiedName: String,
id: Int,
val default: T? = null
) : AbstractArrayMapOwner.AbstractArrayMapAccessor(id), ReadOnlyProperty, V> {
override fun getValue(thisRef: AbstractArrayMapOwner, property: KProperty<*>): T {
return extractValue(thisRef)
?: default
?: error("No '$keyQualifiedName'($id) in array owner: $thisRef")
}
}
class NullableArrayMapAccessor(
id: Int
) : AbstractArrayMapOwner.AbstractArrayMapAccessor(id), ReadOnlyProperty, V?> {
override fun getValue(thisRef: AbstractArrayMapOwner, property: KProperty<*>): T? {
return extractValue(thisRef)
}
}
abstract class TypeRegistry {
private val idPerType = ConcurrentHashMap()
private val idCounter = AtomicInteger(0)
fun generateAccessor(kClass: KClass, default: T? = null): ArrayMapAccessor {
return ArrayMapAccessor(kClass.qualifiedName!!, getId(kClass), default)
}
fun generateAccessor(keyQualifiedName: String, default: T? = null): ArrayMapAccessor {
return ArrayMapAccessor(keyQualifiedName, getId(keyQualifiedName), default)
}
fun generateNullableAccessor(kClass: KClass): NullableArrayMapAccessor {
return NullableArrayMapAccessor(getId(kClass))
}
fun generateAnyNullableAccessor(kClass: KClass): NullableArrayMapAccessor {
return NullableArrayMapAccessor(getId(kClass))
}
fun getId(kClass: KClass): Int {
return getId(kClass.qualifiedName!!)
}
fun getId(keyQualifiedName: String): Int {
return idPerType.customComputeIfAbsent(keyQualifiedName) { idCounter.getAndIncrement() }
}
/*
* This function is needed for compatibility with JDK 6
* ArrayMap and other infrastructure is used in KotlinType, declared in :core:descriptors module, which is
* compiled against JDK 6 (because it's used in kotlin-reflect, which is still compatible with Java 6)
* So the problem is that JDK 6 does not have thread-safe computeIfAbsent for ConcurrentHashMap,
* and we need this method to add ability to provide thread-safe implementation by hand
*/
abstract fun ConcurrentHashMap.customComputeIfAbsent(
key: String,
compute: (String) -> Int
): Int
fun allValuesThreadUnsafeForRendering(): Map {
return idPerType
}
protected val indices: Collection
get() = idPerType.values
}