489 lines
17 KiB
Java
489 lines
17 KiB
Java
|
package com.google.common.collect;
|
||
|
|
||
|
import com.google.common.base.Objects;
|
||
|
import com.google.common.base.Preconditions;
|
||
|
import com.google.common.primitives.Ints;
|
||
|
import java.io.IOException;
|
||
|
import java.io.InvalidObjectException;
|
||
|
import java.io.ObjectInputStream;
|
||
|
import java.io.ObjectOutputStream;
|
||
|
import java.io.Serializable;
|
||
|
import java.util.AbstractSet;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.Collection;
|
||
|
import java.util.Collections;
|
||
|
import java.util.ConcurrentModificationException;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.LinkedHashSet;
|
||
|
import java.util.NoSuchElementException;
|
||
|
import java.util.Set;
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
/* loaded from: classes2.dex */
|
||
|
public class CompactHashSet<E> extends AbstractSet<E> implements Serializable {
|
||
|
static final double HASH_FLOODING_FPP = 0.001d;
|
||
|
private static final int MAX_HASH_BUCKET_LENGTH = 9;
|
||
|
transient Object[] elements;
|
||
|
private transient int[] entries;
|
||
|
private transient int metadata;
|
||
|
private transient int size;
|
||
|
private transient Object table;
|
||
|
|
||
|
int adjustAfterRemove(int i, int i2) {
|
||
|
return i - 1;
|
||
|
}
|
||
|
|
||
|
public static <E> CompactHashSet<E> create() {
|
||
|
return new CompactHashSet<>();
|
||
|
}
|
||
|
|
||
|
public static <E> CompactHashSet<E> create(Collection<? extends E> collection) {
|
||
|
CompactHashSet<E> createWithExpectedSize = createWithExpectedSize(collection.size());
|
||
|
createWithExpectedSize.addAll(collection);
|
||
|
return createWithExpectedSize;
|
||
|
}
|
||
|
|
||
|
@SafeVarargs
|
||
|
public static <E> CompactHashSet<E> create(E... eArr) {
|
||
|
CompactHashSet<E> createWithExpectedSize = createWithExpectedSize(eArr.length);
|
||
|
Collections.addAll(createWithExpectedSize, eArr);
|
||
|
return createWithExpectedSize;
|
||
|
}
|
||
|
|
||
|
public static <E> CompactHashSet<E> createWithExpectedSize(int i) {
|
||
|
return new CompactHashSet<>(i);
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public CompactHashSet() {
|
||
|
init(3);
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public CompactHashSet(int i) {
|
||
|
init(i);
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public void init(int i) {
|
||
|
Preconditions.checkArgument(i >= 0, "Expected size must be >= 0");
|
||
|
this.metadata = Ints.constrainToRange(i, 1, 1073741823);
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public int allocArrays() {
|
||
|
Preconditions.checkState(needsAllocArrays(), "Arrays already allocated");
|
||
|
int i = this.metadata;
|
||
|
int tableSize = CompactHashing.tableSize(i);
|
||
|
this.table = CompactHashing.createTable(tableSize);
|
||
|
setHashTableMask(tableSize - 1);
|
||
|
this.entries = new int[i];
|
||
|
this.elements = new Object[i];
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
Set<E> delegateOrNull() {
|
||
|
Object obj = this.table;
|
||
|
if (obj instanceof Set) {
|
||
|
return (Set) obj;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
private Set<E> createHashFloodingResistantDelegate(int i) {
|
||
|
return new LinkedHashSet(i, 1.0f);
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
/* JADX WARN: Multi-variable type inference failed */
|
||
|
public Set<E> convertToHashFloodingResistantImplementation() {
|
||
|
Set<E> createHashFloodingResistantDelegate = createHashFloodingResistantDelegate(hashTableMask() + 1);
|
||
|
int firstEntryIndex = firstEntryIndex();
|
||
|
while (firstEntryIndex >= 0) {
|
||
|
createHashFloodingResistantDelegate.add(this.elements[firstEntryIndex]);
|
||
|
firstEntryIndex = getSuccessor(firstEntryIndex);
|
||
|
}
|
||
|
this.table = createHashFloodingResistantDelegate;
|
||
|
this.entries = null;
|
||
|
this.elements = null;
|
||
|
incrementModCount();
|
||
|
return createHashFloodingResistantDelegate;
|
||
|
}
|
||
|
|
||
|
boolean isUsingHashFloodingResistance() {
|
||
|
return delegateOrNull() != null;
|
||
|
}
|
||
|
|
||
|
private void setHashTableMask(int i) {
|
||
|
this.metadata = CompactHashing.maskCombine(this.metadata, 32 - Integer.numberOfLeadingZeros(i), 31);
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public boolean add(E e) {
|
||
|
if (needsAllocArrays()) {
|
||
|
allocArrays();
|
||
|
}
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
return delegateOrNull.add(e);
|
||
|
}
|
||
|
int[] iArr = this.entries;
|
||
|
Object[] objArr = this.elements;
|
||
|
int i = this.size;
|
||
|
int i2 = i + 1;
|
||
|
int smearedHash = Hashing.smearedHash(e);
|
||
|
int hashTableMask = hashTableMask();
|
||
|
int i3 = smearedHash & hashTableMask;
|
||
|
int tableGet = CompactHashing.tableGet(this.table, i3);
|
||
|
if (tableGet != 0) {
|
||
|
int hashPrefix = CompactHashing.getHashPrefix(smearedHash, hashTableMask);
|
||
|
int i4 = 0;
|
||
|
while (true) {
|
||
|
int i5 = tableGet - 1;
|
||
|
int i6 = iArr[i5];
|
||
|
if (CompactHashing.getHashPrefix(i6, hashTableMask) == hashPrefix && Objects.equal(e, objArr[i5])) {
|
||
|
return false;
|
||
|
}
|
||
|
int next = CompactHashing.getNext(i6, hashTableMask);
|
||
|
i4++;
|
||
|
if (next != 0) {
|
||
|
tableGet = next;
|
||
|
} else {
|
||
|
if (i4 >= 9) {
|
||
|
return convertToHashFloodingResistantImplementation().add(e);
|
||
|
}
|
||
|
if (i2 > hashTableMask) {
|
||
|
hashTableMask = resizeTable(hashTableMask, CompactHashing.newCapacity(hashTableMask), smearedHash, i);
|
||
|
} else {
|
||
|
iArr[i5] = CompactHashing.maskCombine(i6, i2, hashTableMask);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else if (i2 > hashTableMask) {
|
||
|
hashTableMask = resizeTable(hashTableMask, CompactHashing.newCapacity(hashTableMask), smearedHash, i);
|
||
|
} else {
|
||
|
CompactHashing.tableSet(this.table, i3, i2);
|
||
|
}
|
||
|
resizeMeMaybe(i2);
|
||
|
insertEntry(i, e, smearedHash, hashTableMask);
|
||
|
this.size = i2;
|
||
|
incrementModCount();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public void insertEntry(int i, E e, int i2, int i3) {
|
||
|
this.entries[i] = CompactHashing.maskCombine(i2, 0, i3);
|
||
|
this.elements[i] = e;
|
||
|
}
|
||
|
|
||
|
private void resizeMeMaybe(int i) {
|
||
|
int min;
|
||
|
int length = this.entries.length;
|
||
|
if (i <= length || (min = Math.min(1073741823, (Math.max(1, length >>> 1) + length) | 1)) == length) {
|
||
|
return;
|
||
|
}
|
||
|
resizeEntries(min);
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public void resizeEntries(int i) {
|
||
|
this.entries = Arrays.copyOf(this.entries, i);
|
||
|
this.elements = Arrays.copyOf(this.elements, i);
|
||
|
}
|
||
|
|
||
|
private int resizeTable(int i, int i2, int i3, int i4) {
|
||
|
Object createTable = CompactHashing.createTable(i2);
|
||
|
int i5 = i2 - 1;
|
||
|
if (i4 != 0) {
|
||
|
CompactHashing.tableSet(createTable, i3 & i5, i4 + 1);
|
||
|
}
|
||
|
Object obj = this.table;
|
||
|
int[] iArr = this.entries;
|
||
|
for (int i6 = 0; i6 <= i; i6++) {
|
||
|
int tableGet = CompactHashing.tableGet(obj, i6);
|
||
|
while (tableGet != 0) {
|
||
|
int i7 = tableGet - 1;
|
||
|
int i8 = iArr[i7];
|
||
|
int hashPrefix = CompactHashing.getHashPrefix(i8, i) | i6;
|
||
|
int i9 = hashPrefix & i5;
|
||
|
int tableGet2 = CompactHashing.tableGet(createTable, i9);
|
||
|
CompactHashing.tableSet(createTable, i9, tableGet);
|
||
|
iArr[i7] = CompactHashing.maskCombine(hashPrefix, tableGet2, i5);
|
||
|
tableGet = CompactHashing.getNext(i8, i);
|
||
|
}
|
||
|
}
|
||
|
this.table = createTable;
|
||
|
setHashTableMask(i5);
|
||
|
return i5;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public boolean contains(Object obj) {
|
||
|
if (needsAllocArrays()) {
|
||
|
return false;
|
||
|
}
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
return delegateOrNull.contains(obj);
|
||
|
}
|
||
|
int smearedHash = Hashing.smearedHash(obj);
|
||
|
int hashTableMask = hashTableMask();
|
||
|
int tableGet = CompactHashing.tableGet(this.table, smearedHash & hashTableMask);
|
||
|
if (tableGet == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
int hashPrefix = CompactHashing.getHashPrefix(smearedHash, hashTableMask);
|
||
|
do {
|
||
|
int i = tableGet - 1;
|
||
|
int i2 = this.entries[i];
|
||
|
if (CompactHashing.getHashPrefix(i2, hashTableMask) == hashPrefix && Objects.equal(obj, this.elements[i])) {
|
||
|
return true;
|
||
|
}
|
||
|
tableGet = CompactHashing.getNext(i2, hashTableMask);
|
||
|
} while (tableGet != 0);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public boolean remove(Object obj) {
|
||
|
if (needsAllocArrays()) {
|
||
|
return false;
|
||
|
}
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
return delegateOrNull.remove(obj);
|
||
|
}
|
||
|
int hashTableMask = hashTableMask();
|
||
|
int remove = CompactHashing.remove(obj, null, hashTableMask, this.table, this.entries, this.elements, null);
|
||
|
if (remove == -1) {
|
||
|
return false;
|
||
|
}
|
||
|
moveLastEntry(remove, hashTableMask);
|
||
|
this.size--;
|
||
|
incrementModCount();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public void moveLastEntry(int i, int i2) {
|
||
|
int size = size();
|
||
|
int i3 = size - 1;
|
||
|
if (i < i3) {
|
||
|
Object[] objArr = this.elements;
|
||
|
Object obj = objArr[i3];
|
||
|
objArr[i] = obj;
|
||
|
objArr[i3] = null;
|
||
|
int[] iArr = this.entries;
|
||
|
iArr[i] = iArr[i3];
|
||
|
iArr[i3] = 0;
|
||
|
int smearedHash = Hashing.smearedHash(obj) & i2;
|
||
|
int tableGet = CompactHashing.tableGet(this.table, smearedHash);
|
||
|
if (tableGet == size) {
|
||
|
CompactHashing.tableSet(this.table, smearedHash, i + 1);
|
||
|
return;
|
||
|
}
|
||
|
while (true) {
|
||
|
int i4 = tableGet - 1;
|
||
|
int i5 = this.entries[i4];
|
||
|
int next = CompactHashing.getNext(i5, i2);
|
||
|
if (next == size) {
|
||
|
this.entries[i4] = CompactHashing.maskCombine(i5, i + 1, i2);
|
||
|
return;
|
||
|
}
|
||
|
tableGet = next;
|
||
|
}
|
||
|
} else {
|
||
|
this.elements[i] = null;
|
||
|
this.entries[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int firstEntryIndex() {
|
||
|
return isEmpty() ? -1 : 0;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.lang.Iterable, java.util.Set
|
||
|
public Iterator<E> iterator() {
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
return delegateOrNull.iterator();
|
||
|
}
|
||
|
return new Iterator<E>(this) { // from class: com.google.common.collect.CompactHashSet.1
|
||
|
int currentIndex;
|
||
|
int expectedMetadata;
|
||
|
int indexToRemove = -1;
|
||
|
final CompactHashSet this$0;
|
||
|
|
||
|
{
|
||
|
this.this$0 = this;
|
||
|
this.expectedMetadata = this.metadata;
|
||
|
this.currentIndex = this.firstEntryIndex();
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public E next() {
|
||
|
checkForConcurrentModification();
|
||
|
if (!hasNext()) {
|
||
|
throw new NoSuchElementException();
|
||
|
}
|
||
|
this.indexToRemove = this.currentIndex;
|
||
|
Object[] objArr = this.this$0.elements;
|
||
|
int i = this.currentIndex;
|
||
|
E e = (E) objArr[i];
|
||
|
this.currentIndex = this.this$0.getSuccessor(i);
|
||
|
return e;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public void remove() {
|
||
|
checkForConcurrentModification();
|
||
|
CollectPreconditions.checkRemove(this.indexToRemove >= 0);
|
||
|
incrementExpectedModCount();
|
||
|
CompactHashSet compactHashSet = this.this$0;
|
||
|
compactHashSet.remove(compactHashSet.elements[this.indexToRemove]);
|
||
|
this.currentIndex = this.this$0.adjustAfterRemove(this.currentIndex, this.indexToRemove);
|
||
|
this.indexToRemove = -1;
|
||
|
}
|
||
|
|
||
|
private void checkForConcurrentModification() {
|
||
|
if (this.this$0.metadata != this.expectedMetadata) {
|
||
|
throw new ConcurrentModificationException();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void incrementExpectedModCount() {
|
||
|
this.expectedMetadata += 32;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public boolean hasNext() {
|
||
|
return this.currentIndex >= 0;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public int size() {
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
return delegateOrNull != null ? delegateOrNull.size() : this.size;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public boolean isEmpty() {
|
||
|
return size() == 0;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public Object[] toArray() {
|
||
|
if (needsAllocArrays()) {
|
||
|
return new Object[0];
|
||
|
}
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
return delegateOrNull != null ? delegateOrNull.toArray() : Arrays.copyOf(this.elements, this.size);
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public <T> T[] toArray(T[] tArr) {
|
||
|
if (needsAllocArrays()) {
|
||
|
if (tArr.length > 0) {
|
||
|
tArr[0] = null;
|
||
|
}
|
||
|
return tArr;
|
||
|
}
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
return (T[]) delegateOrNull.toArray(tArr);
|
||
|
}
|
||
|
return (T[]) ObjectArrays.toArrayImpl(this.elements, 0, this.size, tArr);
|
||
|
}
|
||
|
|
||
|
public void trimToSize() {
|
||
|
if (needsAllocArrays()) {
|
||
|
return;
|
||
|
}
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
Set<E> createHashFloodingResistantDelegate = createHashFloodingResistantDelegate(size());
|
||
|
createHashFloodingResistantDelegate.addAll(delegateOrNull);
|
||
|
this.table = createHashFloodingResistantDelegate;
|
||
|
return;
|
||
|
}
|
||
|
int i = this.size;
|
||
|
if (i < this.entries.length) {
|
||
|
resizeEntries(i);
|
||
|
}
|
||
|
int tableSize = CompactHashing.tableSize(i);
|
||
|
int hashTableMask = hashTableMask();
|
||
|
if (tableSize < hashTableMask) {
|
||
|
resizeTable(hashTableMask, tableSize, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // java.util.AbstractCollection, java.util.Collection, java.util.Set
|
||
|
public void clear() {
|
||
|
if (needsAllocArrays()) {
|
||
|
return;
|
||
|
}
|
||
|
incrementModCount();
|
||
|
Set<E> delegateOrNull = delegateOrNull();
|
||
|
if (delegateOrNull != null) {
|
||
|
this.metadata = Ints.constrainToRange(size(), 3, 1073741823);
|
||
|
delegateOrNull.clear();
|
||
|
this.table = null;
|
||
|
this.size = 0;
|
||
|
return;
|
||
|
}
|
||
|
Arrays.fill(this.elements, 0, this.size, (Object) null);
|
||
|
CompactHashing.tableClear(this.table);
|
||
|
Arrays.fill(this.entries, 0, this.size, 0);
|
||
|
this.size = 0;
|
||
|
}
|
||
|
|
||
|
private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
|
||
|
objectOutputStream.defaultWriteObject();
|
||
|
objectOutputStream.writeInt(size());
|
||
|
Iterator<E> it = iterator();
|
||
|
while (it.hasNext()) {
|
||
|
objectOutputStream.writeObject(it.next());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* JADX WARN: Multi-variable type inference failed */
|
||
|
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
|
||
|
objectInputStream.defaultReadObject();
|
||
|
int readInt = objectInputStream.readInt();
|
||
|
if (readInt < 0) {
|
||
|
StringBuilder sb = new StringBuilder(25);
|
||
|
sb.append("Invalid size: ");
|
||
|
sb.append(readInt);
|
||
|
throw new InvalidObjectException(sb.toString());
|
||
|
}
|
||
|
init(readInt);
|
||
|
for (int i = 0; i < readInt; i++) {
|
||
|
add(objectInputStream.readObject());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public boolean needsAllocArrays() {
|
||
|
return this.table == null;
|
||
|
}
|
||
|
|
||
|
void incrementModCount() {
|
||
|
this.metadata += 32;
|
||
|
}
|
||
|
|
||
|
int getSuccessor(int i) {
|
||
|
int i2 = i + 1;
|
||
|
if (i2 >= this.size) {
|
||
|
return -1;
|
||
|
}
|
||
|
return i2;
|
||
|
}
|
||
|
|
||
|
private int hashTableMask() {
|
||
|
return (1 << (this.metadata & 31)) - 1;
|
||
|
}
|
||
|
}
|