Move AttributeArray to compiler.common so frontend extension can share it
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
82455c849d
commit
62bde2d686
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
sealed class ArrayMap<T : Any> : Iterable<T> {
|
||||
abstract val size: Int
|
||||
|
||||
abstract operator fun set(index: Int, value: T)
|
||||
abstract operator fun get(index: Int): T?
|
||||
|
||||
abstract fun copy(): ArrayMap<T>
|
||||
}
|
||||
|
||||
internal object EmptyArrayMap : ArrayMap<Nothing>() {
|
||||
override val size: Int
|
||||
get() = 0
|
||||
|
||||
override fun set(index: Int, value: Nothing) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun get(index: Int): Nothing? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun copy(): ArrayMap<Nothing> = this
|
||||
|
||||
override fun iterator(): Iterator<Nothing> {
|
||||
return object : Iterator<Nothing> {
|
||||
override fun hasNext(): Boolean = false
|
||||
|
||||
override fun next(): Nothing = throw NoSuchElementException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class OneElementArrayMap<T : Any>(val value: T, val index: Int) : ArrayMap<T>() {
|
||||
override val size: Int
|
||||
get() = 1
|
||||
|
||||
override fun set(index: Int, value: T) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
override fun get(index: Int): T? {
|
||||
return if (index == this.index) value else null
|
||||
}
|
||||
|
||||
override fun copy(): ArrayMap<T> = OneElementArrayMap(value, index)
|
||||
|
||||
override fun iterator(): Iterator<T> {
|
||||
return object : Iterator<T> {
|
||||
private var notVisited = true
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return notVisited
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
if (notVisited) {
|
||||
notVisited = false
|
||||
return value
|
||||
} else {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ArrayMapImpl<T : Any> private constructor(
|
||||
private var data: Array<Any?>,
|
||||
initialSize: Int
|
||||
) : ArrayMap<T>() {
|
||||
companion object {
|
||||
private const val DEFAULT_SIZE = 20
|
||||
private const val INCREASE_K = 2
|
||||
}
|
||||
|
||||
constructor() : this(arrayOfNulls<Any>(DEFAULT_SIZE), 0)
|
||||
|
||||
override var size: Int = initialSize
|
||||
private set
|
||||
|
||||
|
||||
private fun ensureCapacity(index: Int) {
|
||||
if (data.size <= index) {
|
||||
data = data.copyOf(data.size * INCREASE_K)
|
||||
}
|
||||
}
|
||||
|
||||
override operator fun set(index: Int, value: T) {
|
||||
ensureCapacity(index)
|
||||
if (data[index] == null) {
|
||||
size++
|
||||
}
|
||||
data[index] = value
|
||||
}
|
||||
|
||||
override operator fun get(index: Int): T? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return data.getOrNull(index) as T?
|
||||
}
|
||||
|
||||
override fun copy(): ArrayMap<T> = ArrayMapImpl(data.copyOf(), size)
|
||||
|
||||
override fun iterator(): Iterator<T> {
|
||||
return object : AbstractIterator<T>() {
|
||||
private var index = -1
|
||||
|
||||
override fun computeNext() {
|
||||
do {
|
||||
index++
|
||||
} while (index < data.size && data[index] == null)
|
||||
if (index >= data.size) {
|
||||
done()
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
setNext(data[index] as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(index: Int) {
|
||||
if (data[index] != null) {
|
||||
size--
|
||||
}
|
||||
data[index] = null
|
||||
}
|
||||
|
||||
fun entries(): List<Entry<T>> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return data.mapIndexedNotNull { index, value -> if (value != null) Entry(index, value as T) else null }
|
||||
}
|
||||
|
||||
data class Entry<T>(override val key: Int, override val value: T) : Map.Entry<Int, T>
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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<K : Any, V : Any> : Iterable<V> {
|
||||
protected abstract val arrayMap: ArrayMap<V>
|
||||
protected abstract val typeRegistry: TypeRegistry<K, V>
|
||||
|
||||
abstract class AbstractArrayMapAccessor<K : Any, V : Any, T : V>(
|
||||
protected val key: KClass<out K>,
|
||||
protected val id: Int
|
||||
) {
|
||||
protected fun extractValue(thisRef: AbstractArrayMapOwner<K, V>): T? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return thisRef.arrayMap[id] as T?
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun registerComponent(tClass: KClass<out K>, value: V)
|
||||
|
||||
final override fun iterator(): Iterator<V> = arrayMap.iterator()
|
||||
|
||||
fun isEmpty(): Boolean = arrayMap.size == 0
|
||||
|
||||
fun isNotEmpty(): Boolean = arrayMap.size != 0
|
||||
|
||||
operator fun get(index: Int): V? = arrayMap[index]
|
||||
}
|
||||
|
||||
class ArrayMapAccessor<K : Any, V : Any, T : V>(
|
||||
key: KClass<out K>,
|
||||
id: Int,
|
||||
val default: T? = null
|
||||
) : AbstractArrayMapOwner.AbstractArrayMapAccessor<K, V, T>(key, id), ReadOnlyProperty<AbstractArrayMapOwner<K, V>, V> {
|
||||
override fun getValue(thisRef: AbstractArrayMapOwner<K, V>, property: KProperty<*>): T {
|
||||
return extractValue(thisRef)
|
||||
?: default
|
||||
?: error("No '$key'($id) in array owner: $thisRef")
|
||||
}
|
||||
}
|
||||
|
||||
class NullableArrayMapAccessor<K : Any, V : Any, T : V>(
|
||||
key: KClass<out K>,
|
||||
id: Int
|
||||
) : AbstractArrayMapOwner.AbstractArrayMapAccessor<K, V, T>(key, id), ReadOnlyProperty<AbstractArrayMapOwner<K, V>, V?> {
|
||||
override fun getValue(thisRef: AbstractArrayMapOwner<K, V>, property: KProperty<*>): T? {
|
||||
return extractValue(thisRef)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TypeRegistry<K : Any, V : Any> {
|
||||
private val idPerType = ConcurrentHashMap<KClass<out K>, Int>()
|
||||
private val idCounter = AtomicInteger(0)
|
||||
|
||||
|
||||
fun <T : V, KK : K> generateAccessor(kClass: KClass<KK>, default: T? = null): ArrayMapAccessor<K, V, T> {
|
||||
return ArrayMapAccessor(kClass, getId(kClass), default)
|
||||
}
|
||||
|
||||
fun <T : V, KK : K> generateNullableAccessor(kClass: KClass<KK>): NullableArrayMapAccessor<K, V, T> {
|
||||
return NullableArrayMapAccessor(kClass, getId(kClass))
|
||||
}
|
||||
|
||||
fun <KK : K> generateAnyNullableAccessor(kClass: KClass<KK>): NullableArrayMapAccessor<K, V, *> {
|
||||
return NullableArrayMapAccessor(kClass, getId(kClass))
|
||||
}
|
||||
|
||||
fun <T : K> getId(kClass: KClass<T>): Int {
|
||||
return idPerType.computeIfAbsent(kClass) { idCounter.getAndIncrement() }
|
||||
}
|
||||
|
||||
fun allValuesThreadUnsafeForRendering(): Map<KClass<out K>, Int> {
|
||||
return idPerType
|
||||
}
|
||||
|
||||
protected val indices: Collection<Int>
|
||||
get() = idPerType.values
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* [AttributeArrayOwner] based on different implementations of [ArrayMap] and switches them
|
||||
* depending on array map fullness
|
||||
* [AttributeArrayOwner] can be used in classes with many instances,
|
||||
* like user data for Fir elements or attributes for cone types
|
||||
*
|
||||
* Note that you can remove attributes from [AttributeArrayOwner] despite
|
||||
* from components in [ComponentArrayOwner]
|
||||
*/
|
||||
abstract class AttributeArrayOwner<K : Any, T : Any> protected constructor(
|
||||
arrayMap: ArrayMap<T>
|
||||
) : AbstractArrayMapOwner<K, T>() {
|
||||
final override var arrayMap: ArrayMap<T> = arrayMap
|
||||
private set
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
constructor() : this(EmptyArrayMap as ArrayMap<T>)
|
||||
|
||||
final override fun registerComponent(tClass: KClass<out K>, value: T) {
|
||||
val id = typeRegistry.getId(tClass)
|
||||
when (arrayMap.size) {
|
||||
0 -> {
|
||||
arrayMap = OneElementArrayMap(value, id)
|
||||
return
|
||||
}
|
||||
|
||||
1 -> {
|
||||
val map = arrayMap as OneElementArrayMap<T>
|
||||
if (map.index == id) {
|
||||
arrayMap = OneElementArrayMap(value, id)
|
||||
return
|
||||
} else {
|
||||
arrayMap = ArrayMapImpl()
|
||||
arrayMap[map.index] = map.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrayMap[id] = value
|
||||
}
|
||||
|
||||
protected fun removeComponent(tClass: KClass<out K>) {
|
||||
val id = typeRegistry.getId(tClass)
|
||||
if (arrayMap[id] == null) return
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
when (arrayMap.size) {
|
||||
1 -> arrayMap = EmptyArrayMap as ArrayMap<T>
|
||||
else -> {
|
||||
val map = arrayMap as ArrayMapImpl<T>
|
||||
map.remove(id)
|
||||
if (map.size == 1) {
|
||||
val (index, value) = map.entries().first()
|
||||
arrayMap = OneElementArrayMap(value, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* [ComponentArrayOwner] based on [ArrayMap] with flexible size and should be used for
|
||||
* storing services in entities with limited number of instances, like FirSession
|
||||
*/
|
||||
abstract class ComponentArrayOwner<K : Any, V : Any> : AbstractArrayMapOwner<K, V>() {
|
||||
final override val arrayMap: ArrayMap<V> =
|
||||
ArrayMapImpl()
|
||||
|
||||
final override fun registerComponent(tClass: KClass<out K>, value: V) {
|
||||
arrayMap[typeRegistry.getId(tClass)] = value
|
||||
}
|
||||
|
||||
protected operator fun get(key: KClass<out K>): V {
|
||||
val id = typeRegistry.getId(key)
|
||||
return arrayMap[id] ?: error("No '$key'($id) component in array: $this")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.lang.ref.WeakReference
|
||||
|
||||
class WeakPair<K, V>(first: K, second: V) {
|
||||
private val firstReference: WeakReference<K> = WeakReference(first)
|
||||
private val secondReference: WeakReference<V> = WeakReference(second)
|
||||
|
||||
val first: K?
|
||||
get() = firstReference.get()
|
||||
|
||||
val second: V?
|
||||
get() = secondReference.get()
|
||||
}
|
||||
|
||||
operator fun <K, V> WeakPair<K, V>?.component1(): K? {
|
||||
return this?.first
|
||||
}
|
||||
|
||||
operator fun <K, V> WeakPair<K, V>?.component2(): V? {
|
||||
return this?.second
|
||||
}
|
||||
Reference in New Issue
Block a user