Introduce SmartSet, an optimized Set implementation
Using it instead of LinkedHashSet for overridden descriptors optimizes memory retained between analysis and codegen by ~5%
This commit is contained in:
+6
-2
@@ -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<TypeParameterDescriptor> 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<FunctionDescriptor> overriddenFunctions = new LinkedHashSet<FunctionDescriptor>(); // LinkedHashSet is essential here
|
||||
private final Set<FunctionDescriptor> overriddenFunctions = SmartSet.create();
|
||||
private final FunctionDescriptor original;
|
||||
private final Kind kind;
|
||||
|
||||
|
||||
+2
-1
@@ -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<PropertyDescriptor> overriddenProperties = new LinkedHashSet<PropertyDescriptor>(); // LinkedHashSet is essential here
|
||||
private final Set<PropertyDescriptor> overriddenProperties = SmartSet.create();
|
||||
private final PropertyDescriptor original;
|
||||
private final Kind kind;
|
||||
private final boolean lateInit;
|
||||
|
||||
+2
-2
@@ -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<JetType> upperBounds = new LinkedHashSet<JetType>();
|
||||
private final Set<JetType> upperBounds = SmartSet.create();
|
||||
private boolean initialized = false;
|
||||
|
||||
private TypeParameterDescriptorImpl(
|
||||
|
||||
@@ -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<T> private constructor() : AbstractSet<T>() {
|
||||
companion object {
|
||||
private val ARRAY_THRESHOLD = 5
|
||||
|
||||
@JvmStatic
|
||||
fun create<T>() = SmartSet<T>()
|
||||
|
||||
@JvmStatic
|
||||
fun create<T>(set: Set<T>) = SmartSet<T>().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<T> = when {
|
||||
size == 0 -> emptySet<T>().iterator()
|
||||
size == 1 -> SingletonIterator(data as T)
|
||||
size < ARRAY_THRESHOLD -> (data as Array<T>).iterator()
|
||||
else -> (data as MutableSet<T>).iterator()
|
||||
} as MutableIterator<T>
|
||||
|
||||
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<T>
|
||||
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<T>
|
||||
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<T>
|
||||
else -> o in data as Set<T>
|
||||
}
|
||||
|
||||
private class SingletonIterator<T>(private val element: T) : Iterator<T> {
|
||||
private var hasNext = true
|
||||
|
||||
override fun next(): T =
|
||||
if (hasNext) {
|
||||
hasNext = false
|
||||
element
|
||||
}
|
||||
else throw NoSuchElementException()
|
||||
|
||||
override fun hasNext() = hasNext
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user