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:
Alexander Udalov
2015-08-05 03:58:06 +03:00
parent 57c006a1c6
commit c3cb6b62f4
4 changed files with 112 additions and 5 deletions
@@ -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;
@@ -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;
@@ -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
}
}