Add support of hashing strategy in ObjectLinkedOpenHashSet collection

GitOrigin-RevId: 1281ca61e0c40d8e5207cfff314826b680296ddb
This commit is contained in:
Mikhail Mazurkevich
2019-08-22 01:50:10 +03:00
committed by intellij-monorepo-bot
parent e6437b2375
commit f64e3651ce
6 changed files with 128 additions and 45 deletions
@@ -38,7 +38,7 @@ public final class FilesDelta {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.fs.FilesDelta");
private final ReentrantLock myDataLock = new ReentrantLock();
private final Set<String> myDeletedPaths = new ObjectLinkedOpenHashSet<>();
private final Set<String> myDeletedPaths = new ObjectLinkedOpenHashSet<>(FileUtil.PATH_HASHING_STRATEGY);
private final Map<BuildRootDescriptor, Set<File>> myFilesToRecompile = new LinkedHashMap<>();
public void lockData(){
@@ -110,13 +110,13 @@ public final class FilesDelta {
if (descriptor != null) {
files = myFilesToRecompile.get(descriptor);
if (files == null) {
files = new ObjectLinkedOpenHashSet<>();
files = new ObjectLinkedOpenHashSet<>(FileUtil.FILE_HASHING_STRATEGY);
myFilesToRecompile.put(descriptor, files);
}
}
else {
LOG.debug("Cannot find root by " + rootId + ", delta will be skipped");
files = new ObjectLinkedOpenHashSet<>();
files = new ObjectLinkedOpenHashSet<>(FileUtil.FILE_HASHING_STRATEGY);
}
int filesCount = in.readInt();
while (filesCount-- > 0) {
@@ -222,7 +222,7 @@ public final class FilesDelta {
private boolean _addToRecompiled(BuildRootDescriptor root, Collection<? extends File> filesToAdd) {
Set<File> files = myFilesToRecompile.get(root);
if (files == null) {
files = new ObjectLinkedOpenHashSet<>();
files = new ObjectLinkedOpenHashSet<>(FileUtil.FILE_HASHING_STRATEGY);
myFilesToRecompile.put(root, files);
}
return files.addAll(filesToAdd);
@@ -260,7 +260,7 @@ public final class FilesDelta {
lockData();
try {
try {
return new ObjectLinkedOpenHashSet<>(myDeletedPaths) ;
return new ObjectLinkedOpenHashSet<>(myDeletedPaths, FileUtil.PATH_HASHING_STRATEGY) ;
}
finally {
myDeletedPaths.clear();
@@ -220,7 +220,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
@NotNull OutputConsumer outputConsumer,
@NotNull JavaCompilingTool compilingTool) throws ProjectBuildException, IOException {
try {
final Set<File> filesToCompile = new ObjectLinkedOpenHashSet<>();
final Set<File> filesToCompile = new ObjectLinkedOpenHashSet<>(FileUtil.FILE_HASHING_STRATEGY);
dirtyFilesHolder.processDirtyFiles((target, file, descriptor) -> {
if (JAVA_SOURCES_FILTER.accept(file) && ourCompilableModuleTypes.contains(target.getModule().getModuleType())) {
@@ -4,7 +4,7 @@ package org.jetbrains.jps.incremental.storage;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.JBIterator;
import com.intellij.util.containers.OrderedSet;
import com.intellij.util.containers.ObjectLinkedOpenHashSet;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.IOUtil;
import org.jetbrains.annotations.NotNull;
@@ -93,7 +93,7 @@ public class OneToManyPathsMapping extends AbstractStateStorage<String, Collecti
@Override
public Collection<String> read(@NotNull DataInput in) throws IOException {
final Set<String> result = new OrderedSet<>(FileUtil.PATH_HASHING_STRATEGY);
final Set<String> result = new ObjectLinkedOpenHashSet<>(FileUtil.PATH_HASHING_STRATEGY);
final DataInputStream stream = (DataInputStream)in;
while (stream.available() > 0) {
final String str = IOUtil.readUTF(stream);
@@ -15,6 +15,7 @@
*/
package com.intellij.util.containers;
import gnu.trove.TObjectHashingStrategy;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@@ -69,10 +70,34 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
*/
private static final float DEFAULT_LOAD_FACTOR = .75f;
private final TObjectHashingStrategy<K> defaultHashingStrategy = new TObjectHashingStrategy<K>() {
/**
* The default implementation of TObjectHashingStrategy:
* it delegates hashing to the Object's hashCode method.
*/
@Override
public final int computeHashCode(K o) {
return o != null ? o.hashCode() : 0;
}
/**
* The default implementation of TObjectHashingStrategy:
* it delegates equality comparisons to the {@link Objects#equals(Object, Object)}
*/
@Override
public final boolean equals(K o1, K o2) {
return Objects.equals(o1, o2);
}
};
/**
* The array of keys.
*/
transient K[] key;
/**
* The strategy used to hash objects in this collection.
*/
protected final TObjectHashingStrategy<K> hashingStrategy;
/**
* The mask for wrapping a position counter.
*/
@@ -121,10 +146,32 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
private final float f;
/**
* Creates a new hash set.
* Creates a new hash set. The actual table size will be the least power of two greater than
* {@code expected}/{@code f}.
*
* <p>
* The actual table size will be the least power of two greater than
* @param expected the expected number of elements in the hash set.
* @param f the load factor.
* @param strategy {@link TObjectHashingStrategy} used to compute hash codes and to compare objects.
*/
@SuppressWarnings("unchecked")
public ObjectLinkedOpenHashSet(final int expected, final float f, TObjectHashingStrategy<K> strategy) {
if (f <= 0 || f > 1) {
throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than or equal to 1");
}
if (expected < 0) {
throw new IllegalArgumentException("The expected number of elements must be nonnegative");
}
this.f = f;
minN = n = arraySize(expected, f);
mask = n - 1;
maxFill = maxFill(n, f);
key = (K[])new Object[n + 1];
link = new long[n + 1];
hashingStrategy = strategy;
}
/**
* Creates a new hash set. The actual table size will be the least power of two greater than
* {@code expected}/{@code f}.
*
* @param expected the expected number of elements in the hash set.
@@ -144,6 +191,7 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
maxFill = maxFill(n, f);
key = (K[])new Object[n + 1];
link = new long[n + 1];
hashingStrategy = defaultHashingStrategy;
}
/**
@@ -155,6 +203,16 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
this(expected, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a new hash set with {@link ObjectLinkedOpenHashSet#DEFAULT_LOAD_FACTOR} as load factor.
*
* @param expected the expected number of elements in the hash set.
* @param strategy {@link TObjectHashingStrategy} used to compute hash codes and to compare objects.
*/
public ObjectLinkedOpenHashSet(final int expected, TObjectHashingStrategy<K> strategy) {
this(expected, DEFAULT_LOAD_FACTOR, strategy);
}
/**
* Creates a new hash set with initial expected
* {@link ObjectLinkedOpenHashSet#DEFAULT_INITIAL_SIZE} elements and
@@ -164,6 +222,14 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a new hash set with initial expected
* @param strategy {@link TObjectHashingStrategy} used to compute hash codes and to compare objects.
*/
public ObjectLinkedOpenHashSet(TObjectHashingStrategy<K> strategy) {
this(DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy);
}
/**
* Creates a new hash set with {@link ObjectLinkedOpenHashSet#DEFAULT_LOAD_FACTOR} as load factor
* copying a given collection.
@@ -175,6 +241,18 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
addAll(c);
}
/**
* Creates a new hash set with {@link ObjectLinkedOpenHashSet#DEFAULT_LOAD_FACTOR} as load factor
* copying a given collection.
*
* @param c a {@link Collection} to be copied into the new hash set.
* @param strategy {@link TObjectHashingStrategy} used to compute hash codes and to compare objects.
*/
public ObjectLinkedOpenHashSet(final Collection<? extends K> c, TObjectHashingStrategy<K> strategy) {
this(c.size(), DEFAULT_LOAD_FACTOR , strategy);
addAll(c);
}
private int realSize() {
return containsNull ? size - 1 : size;
}
@@ -220,12 +298,12 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
K curr;
final K[] key = this.key;
// The starting point.
if ((curr = key[pos = mix(k.hashCode()) & mask]) != null) {
if (curr.equals(k)) {
if ((curr = key[pos = mix(hashingStrategy.computeHashCode(k)) & mask]) != null) {
if (hashingStrategy.equals(curr,k)) {
return false;
}
while ((curr = key[pos = pos + 1 & mask]) != null) {
if (curr.equals(k)) {
if (hashingStrategy.equals(curr, k)) {
return false;
}
}
@@ -275,12 +353,12 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
K curr;
final K[] key = this.key;
// The starting point.
if ((curr = key[pos = mix(k.hashCode()) & mask]) != null) {
if (curr.equals(k)) {
if ((curr = key[pos = mix(hashingStrategy.computeHashCode(k)) & mask]) != null) {
if (hashingStrategy.equals(curr, k)) {
return curr;
}
while ((curr = key[pos = pos + 1 & mask]) != null) {
if (curr.equals(k)) {
if (hashingStrategy.equals(curr, k)) {
return curr;
}
}
@@ -322,7 +400,7 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
key[last] = null;
return;
}
slot = mix(curr.hashCode()) & mask;
slot = mix(hashingStrategy.computeHashCode(curr)) & mask;
if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) {
break;
}
@@ -361,14 +439,15 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
return false;
}
K curr;
final K[] key = this.key;
K key = (K)k;
final K[] keyArray = this.key;
int pos;
// The starting point.
if ((curr = key[pos = mix(k.hashCode()) & mask]) == null) return false;
if (k.equals(curr)) return removeEntry(pos);
if ((curr = keyArray[pos = mix(hashingStrategy.computeHashCode(key)) & mask]) == null) return false;
if (hashingStrategy.equals(key, curr)) return removeEntry(pos);
while (true) {
if ((curr = key[pos = pos + 1 & mask]) == null) return false;
if (k.equals(curr)) return removeEntry(pos);
if ((curr = keyArray[pos = pos + 1 & mask]) == null) return false;
if (hashingStrategy.equals(key, curr)) return removeEntry(pos);
}
}
@@ -378,14 +457,15 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
return containsNull;
}
K curr;
final K[] key = this.key;
K key = (K)k;
final K[] keyArray = this.key;
int pos;
// The starting point.
if ((curr = key[pos = mix(k.hashCode()) & mask]) == null) return false;
if (k.equals(curr)) return true;
if ((curr = keyArray[pos = mix(hashingStrategy.computeHashCode(key)) & mask]) == null) return false;
if (hashingStrategy.equals(key, curr)) return true;
while (true) {
if ((curr = key[pos = pos + 1 & mask]) == null) return false;
if (k.equals(curr)) return true;
if ((curr = keyArray[pos = pos + 1 & mask]) == null) return false;
if (hashingStrategy.equals(key, curr)) return true;
}
}
@@ -400,15 +480,16 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
if (k == null) return key[n]; // This is correct independently of the value of containsNull and of the set
// being custom
K curr;
final K[] key = this.key;
K key = (K)k;
final K[] keyArray = this.key;
int pos;
// The starting point.
if ((curr = key[pos = mix(k.hashCode()) & mask]) == null) return null;
if (k.equals(curr)) return curr;
if ((curr = keyArray[pos = mix(hashingStrategy.computeHashCode(key)) & mask]) == null) return null;
if (hashingStrategy.equals(key, curr)) return curr;
// There's always an unused entry.
while (true) {
if ((curr = key[pos = pos + 1 & mask]) == null) return null;
if (k.equals(curr)) return curr;
if ((curr = keyArray[pos = pos + 1 & mask]) == null) return null;
if (hashingStrategy.equals(key, curr)) return curr;
}
}
@@ -662,7 +743,7 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
key[last] = null;
return;
}
slot = mix(curr.hashCode()) & mask;
slot = mix(hashingStrategy.computeHashCode(curr)) & mask;
if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) {
break;
}
@@ -749,7 +830,7 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
pos = newN;
}
else {
pos = mix(key[i].hashCode()) & mask;
pos = mix(hashingStrategy.computeHashCode(key[i])) & mask;
while (newKey[pos] != null) {
pos = pos + 1 & mask;
}
@@ -825,7 +906,7 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
i++;
}
if (this != key[i]) {
h += key[i].hashCode();
h += hashingStrategy.computeHashCode(key[i]);
}
i++;
}
@@ -901,7 +982,7 @@ public class ObjectLinkedOpenHashSet<K> extends AbstractSet<K> implements Set<K>
containsNull = true;
}
else {
if (key[pos = mix(k.hashCode()) & mask] != null) {
if (key[pos = mix(hashingStrategy.computeHashCode(k)) & mask] != null) {
while (key[pos = pos + 1 & mask] != null) ;
}
}
@@ -6,7 +6,8 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileFilters;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ObjectLinkedOpenHashSet;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
@@ -88,9 +89,9 @@ public class FormsBindingManager extends FormsBuilder {
return exitCode;
}
final Map<File, ModuleBuildTarget> filesToCompile = new LinkedHashMap<>();
final Map<File, ModuleBuildTarget> formsToCompile = new LinkedHashMap<>();
final Map<File, Collection<File>> srcToForms = new LinkedHashMap<>();
final Map<File, ModuleBuildTarget> filesToCompile = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
final Map<File, ModuleBuildTarget> formsToCompile = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
final Map<File, Collection<File>> srcToForms = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
if (!JavaBuilderUtil.isForcedRecompilationAllJavaModules(context) && config.isInstrumentClasses() && FORCE_FORMS_REBUILD_FLAG.get(context, Boolean.FALSE)) {
// force compilation of all forms, but only once per chunk
@@ -208,7 +209,7 @@ public class FormsBindingManager extends FormsBuilder {
}
}
final Set<File> candidates = new ObjectLinkedOpenHashSet<>();
final Set<File> candidates = new THashSet<>(FileUtil.FILE_HASHING_STRATEGY);
for (JavaSourceRootDescriptor rd : targetRoots) {
candidates.addAll(findPossibleSourcesForClass(rd, className));
}
@@ -11,7 +11,8 @@ import com.intellij.uiDesigner.compiler.*;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
import com.intellij.uiDesigner.lw.LwRootContainer;
import com.intellij.util.containers.ObjectLinkedOpenHashSet;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectPaths;
@@ -61,7 +62,7 @@ public class FormsInstrumenter extends FormsBuilder {
return ExitCode.NOTHING_DONE;
}
final Set<File> formsToCompile = new ObjectLinkedOpenHashSet<>();
final Set<File> formsToCompile = new THashSet<>(FileUtil.FILE_HASHING_STRATEGY);
for (Collection<File> files : srcToForms.values()) {
formsToCompile.addAll(files);
}
@@ -124,7 +125,7 @@ public class FormsInstrumenter extends FormsBuilder {
CompileContext context, ModuleChunk chunk, final Map<File, String> chunkSourcePath, final InstrumentationClassFinder finder, Collection<File> forms, OutputConsumer outConsumer
) throws ProjectBuildException {
final Map<File, Collection<File>> instrumented = new LinkedHashMap<>();
final Map<File, Collection<File>> instrumented = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
final Map<String, File> class2form = new HashMap<>();
final MyNestedFormLoader nestedFormsLoader = new MyNestedFormLoader(chunkSourcePath, ProjectPaths.getOutputPathsWithDependents(chunk), finder);