diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt
index 0dc3bdcbe4e..3706691a1d1 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt
@@ -38,7 +38,7 @@ class FirRegisteredExtension
(
class FirExtensionsService(
val session: FirSession
) : ComponentArrayOwner>(), FirSessionComponent {
- companion object : ComponentTypeRegistry>() {
+ companion object : TypeRegistry>() {
inline fun > registeredExtensions(): ReadOnlyProperty> {
val accessor = generateAccessor(P::class)
return object : ReadOnlyProperty> {
@@ -51,7 +51,7 @@ class FirExtensionsService(
private fun createMultimap(): Multimap = LinkedHashMultimap.create()
}
- override val typeRegistry: ComponentTypeRegistry>
+ override val typeRegistry: TypeRegistry>
get() = Companion
fun registerExtensions(extensionClass: KClass
, extensionFactories: List>) {
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt
index ff3528c44bd..e31c9897ffd 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt
@@ -8,16 +8,16 @@ package org.jetbrains.kotlin.fir
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.types.impl.*
-import org.jetbrains.kotlin.fir.utils.ComponentArrayAccessor
+import org.jetbrains.kotlin.fir.utils.ArrayMapAccessor
import org.jetbrains.kotlin.fir.utils.ComponentArrayOwner
-import org.jetbrains.kotlin.fir.utils.ComponentTypeRegistry
+import org.jetbrains.kotlin.fir.utils.TypeRegistry
import org.jetbrains.kotlin.utils.Jsr305State
interface FirSessionComponent
abstract class FirSession(val sessionProvider: FirSessionProvider?) : ComponentArrayOwner() {
- companion object : ComponentTypeRegistry() {
- inline fun sessionComponentAccessor(): ComponentArrayAccessor {
+ companion object : TypeRegistry() {
+ inline fun sessionComponentAccessor(): ArrayMapAccessor {
return generateAccessor(T::class)
}
}
@@ -28,7 +28,7 @@ abstract class FirSession(val sessionProvider: FirSessionProvider?) : ComponentA
val builtinTypes: BuiltinTypes = BuiltinTypes()
- final override val typeRegistry: ComponentTypeRegistry = Companion
+ final override val typeRegistry: TypeRegistry = Companion
}
interface FirSessionProvider {
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationAttributes.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationAttributes.kt
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt
new file mode 100644
index 00000000000..01f4fc63701
--- /dev/null
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2020 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.fir.utils
+
+sealed class ArrayMap {
+ abstract val size: Int
+
+ abstract operator fun set(index: Int, value: T)
+ abstract operator fun get(index: Int): T?
+}
+
+internal object EmptyArrayMap : ArrayMap() {
+ override val size: Int
+ get() = 0
+
+ override fun set(index: Int, value: Nothing) {
+ throw IllegalStateException()
+ }
+
+ override fun get(index: Int): Nothing? {
+ return null
+ }
+}
+
+internal class OneElementArrayMap(val value: T, val index: Int) : ArrayMap() {
+ 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
+ }
+}
+
+internal class ArrayMapImpl : ArrayMap() {
+ companion object {
+ private const val DEFAULT_SIZE = 20
+ private const val INCREASE_K = 2
+ }
+
+ override var size: Int = 0
+ private set
+
+ private var data = arrayOfNulls(DEFAULT_SIZE)
+ 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)
+ data[index] = value
+
+ size++
+ }
+
+ override operator fun get(index: Int): T? {
+ @Suppress("UNCHECKED_CAST")
+ return data.getOrNull(index) as T?
+ }
+}
\ No newline at end of file
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt
new file mode 100644
index 00000000000..391a3f8a9d2
--- /dev/null
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2020 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.fir.utils
+
+import java.util.*
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KClass
+import kotlin.reflect.KProperty
+
+abstract class AbstractArrayMapOwner {
+ protected abstract val arrayMap: ArrayMap
+ protected abstract val typeRegistry: TypeRegistry
+
+ abstract class AbstractArrayMapAccessor(
+ protected val key: KClass,
+ protected val id: Int
+ ) {
+ protected fun extractValue(thisRef: AbstractArrayMapOwner): T? {
+ @Suppress("UNCHECKED_CAST")
+ return thisRef.arrayMap[id] as T?
+ }
+ }
+
+ protected abstract fun registerComponent(tClass: KClass, value: V)
+}
+
+class ArrayMapAccessor(
+ key: KClass,
+ id: Int
+) : AbstractArrayMapOwner.AbstractArrayMapAccessor(key, id), ReadOnlyProperty, V> {
+ override fun getValue(thisRef: AbstractArrayMapOwner, property: KProperty<*>): T {
+ return extractValue(thisRef) ?: error("No '$key'($id) in array owner: $thisRef")
+ }
+}
+
+class NullableArrayMapAccessor(
+ key: KClass,
+ id: Int
+) : AbstractArrayMapOwner.AbstractArrayMapAccessor(key, id), ReadOnlyProperty, V?> {
+ override fun getValue(thisRef: AbstractArrayMapOwner, property: KProperty<*>): T? {
+ return extractValue(thisRef)
+ }
+}
+
+abstract class TypeRegistry {
+ private val idPerType = HashMap, Int>()
+
+ fun generateAccessor(kClass: KClass): ArrayMapAccessor {
+ return ArrayMapAccessor(kClass, getId(kClass))
+ }
+
+ fun generateNullableAccessor(kClass: KClass): NullableArrayMapAccessor {
+ return NullableArrayMapAccessor(kClass, getId(kClass))
+ }
+
+ fun getId(kClass: KClass): Int {
+ return idPerType.getOrPut(kClass) { idPerType.size }
+ }
+}
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/AttributeArrayOwner.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/AttributeArrayOwner.kt
new file mode 100644
index 00000000000..32930a3f9dc
--- /dev/null
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/AttributeArrayOwner.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010-2020 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.fir.utils
+
+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
+ */
+abstract class AttributeArrayOwner : AbstractArrayMapOwner() {
+ @Suppress("UNCHECKED_CAST")
+ final override var arrayMap: ArrayMap = EmptyArrayMap as ArrayMap
+ private set
+
+ final override fun registerComponent(tClass: KClass, value: T) {
+ val id = typeRegistry.getId(tClass)
+ when (arrayMap.size) {
+ 0 -> {
+ arrayMap = OneElementArrayMap(value, id)
+ return
+ }
+
+ 1 -> {
+ arrayMap = ArrayMapImpl().apply {
+ val map = arrayMap as OneElementArrayMap
+ this[map.index] = map.value
+ }
+ }
+ }
+
+ arrayMap[id] = value
+ }
+}
\ No newline at end of file
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArray.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArray.kt
deleted file mode 100644
index 49bbe8b147a..00000000000
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArray.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2010-2020 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.fir.utils
-
-import kotlin.properties.ReadOnlyProperty
-import kotlin.reflect.KClass
-import kotlin.reflect.KProperty
-
-abstract class ComponentArrayOwner {
- internal val componentArray: ComponentArray = ComponentArray()
- protected abstract val typeRegistry: ComponentTypeRegistry
-
- protected fun registerComponent(tClass: KClass, value: V) {
- componentArray[(typeRegistry.getId(tClass))] = value
- }
-
- protected operator fun get(tClass: KClass): V {
- return componentArray[typeRegistry.getId(tClass)]
- }
-}
-
-
-abstract class ComponentTypeRegistry {
- private val idPerType = mutableMapOf, Int>()
-
- fun generateAccessor(kClass: KClass): ComponentArrayAccessor {
- return ComponentArrayAccessor(kClass, getId(kClass))
- }
-
- fun getId(kClass: KClass): Int {
- return idPerType.getOrPut(kClass) { idPerType.size }
- }
-}
-
-
-class ComponentArrayAccessor(
- private val key: KClass,
- private val id: Int
-) : ReadOnlyProperty, V> {
- override fun getValue(thisRef: ComponentArrayOwner, property: KProperty<*>): T {
- @Suppress("UNCHECKED_CAST")
- return thisRef.componentArray[id] as T? ?: error("No '$key'($id) component in session: $thisRef")
- }
-}
-
-class ComponentArray {
- companion object {
- private const val DEFAULT_SIZE = 20
- private const val INCREASE_K = 2
- }
-
- private var data = arrayOfNulls(DEFAULT_SIZE)
- private fun ensureCapacity(index: Int) {
- if (data.size < index) {
- data = data.copyOf(data.size * INCREASE_K)
- }
- }
-
- operator fun set(index: Int, value: T) {
- ensureCapacity(index)
- data[index] = value
- }
-
- operator fun get(index: Int): T {
- @Suppress("UNCHECKED_CAST")
- return data.getOrNull(index) as T
- }
-}
\ No newline at end of file
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArrayOwner.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArrayOwner.kt
new file mode 100644
index 00000000000..26e33286940
--- /dev/null
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArrayOwner.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2020 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.fir.utils
+
+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 : AbstractArrayMapOwner() {
+ final override val arrayMap: ArrayMap =
+ ArrayMapImpl()
+
+ final override fun registerComponent(tClass: KClass, value: V) {
+ arrayMap[typeRegistry.getId(tClass)] = value
+ }
+
+ protected operator fun get(key: KClass): V {
+ val id = typeRegistry.getId(key)
+ return arrayMap[id] ?: error("No '$key'($id) component in array: $this")
+ }
+}
\ No newline at end of file