diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java index cd64001ee9c..04ea67bf6f1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java @@ -26,9 +26,13 @@ import org.jetbrains.kotlin.types.DescriptorSubstitutor; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeSubstitutor; import org.jetbrains.kotlin.types.Variance; +import org.jetbrains.kotlin.utils.SmartSet; import org.jetbrains.kotlin.utils.UtilsPackage; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRootImpl implements FunctionDescriptor { private List typeParameters; @@ -38,7 +42,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo private ReceiverParameterDescriptor dispatchReceiverParameter; private Modality modality; private Visibility visibility = Visibilities.UNKNOWN; - private final Set overriddenFunctions = new LinkedHashSet(); // LinkedHashSet is essential here + private final Set overriddenFunctions = SmartSet.create(); private final FunctionDescriptor original; private final Kind kind; diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java index 301c6c02c16..dc4ab786104 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.DescriptorSubstitutor; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeSubstitutor; import org.jetbrains.kotlin.types.Variance; +import org.jetbrains.kotlin.utils.SmartSet; import java.util.*; @@ -35,7 +36,7 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage. public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImpl implements PropertyDescriptor { private final Modality modality; private Visibility visibility; - private final Set overriddenProperties = new LinkedHashSet(); // LinkedHashSet is essential here + private final Set overriddenProperties = SmartSet.create(); private final PropertyDescriptor original; private final Kind kind; private final boolean lateInit; diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java index 8912060691b..71bbe69ec51 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeParameterDescriptorImpl.java @@ -28,9 +28,9 @@ import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeConstructor; import org.jetbrains.kotlin.types.TypeConstructorImpl; import org.jetbrains.kotlin.types.Variance; +import org.jetbrains.kotlin.utils.SmartSet; import java.util.Collections; -import java.util.LinkedHashSet; import java.util.Set; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns; @@ -63,7 +63,7 @@ public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index, source); } - private final Set upperBounds = new LinkedHashSet(); + private final Set upperBounds = SmartSet.create(); private boolean initialized = false; private TypeParameterDescriptorImpl( diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt new file mode 100644 index 00000000000..b73e0cdad30 --- /dev/null +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/SmartSet.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.utils + +import java.util.* + +/** + * A set which is optimized for small sizes and maintains the order in which the elements were added. + * This set is not synchronized and it does not support removal operations such as [MutableSet.remove], + * [MutableSet.removeAll] and [MutableSet.retainAll]. + * Also, [iterator] returns an iterator which does not support [MutableIterator.remove]. + */ +@Suppress("UNCHECKED_CAST") +class SmartSet private constructor() : AbstractSet() { + companion object { + private val ARRAY_THRESHOLD = 5 + + @JvmStatic + fun create() = SmartSet() + + @JvmStatic + fun create(set: Set) = SmartSet().apply { this.addAll(set) } + } + + // null if size = 0, object if size = 1, array of objects if size < threshold, linked hash set otherwise + private var data: Any? = null + + private var size: Int = 0 + + override fun iterator(): MutableIterator = when { + size == 0 -> emptySet().iterator() + size == 1 -> SingletonIterator(data as T) + size < ARRAY_THRESHOLD -> (data as Array).iterator() + else -> (data as MutableSet).iterator() + } as MutableIterator + + override fun add(e: T): Boolean { + when { + size == 0 -> { + data = e + } + size == 1 -> { + if (data == e) return false + data = arrayOf(data, e) + } + size < ARRAY_THRESHOLD -> { + val arr = data as Array + if (e in arr) return false + data = if (size == ARRAY_THRESHOLD - 1) linkedSetOf(*arr).apply { add(e) } + else Arrays.copyOf(arr, size + 1).apply { set(size() - 1, e) } + } + else -> { + val set = data as MutableSet + if (!set.add(e)) return false + } + } + + size++ + return true + } + + override fun clear() { + data = null + size = 0 + } + + override fun size(): Int = size + + override fun contains(o: Any?): Boolean = when { + size == 0 -> false + size == 1 -> data == o + size < ARRAY_THRESHOLD -> o in data as Array + else -> o in data as Set + } + + private class SingletonIterator(private val element: T) : Iterator { + private var hasNext = true + + override fun next(): T = + if (hasNext) { + hasNext = false + element + } + else throw NoSuchElementException() + + override fun hasNext() = hasNext + } +}