package org.jetbrains.io;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Consumer;
import gnu.trove.THashMap;
import gnu.trove.TObjectObjectProcedure;
import gnu.trove.TObjectProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class InfoMap<E,I extends Info<E>> implements Disposable {
private final IdPool idPool = new IdPool();
private final MyHashMap<E,I> elements;
private final boolean infoIsDisposable;
public InfoMap() {
this(false);
}
public InfoMap(boolean infoIsDisposable) {
elements = new MyHashMap<E, I>();
this.infoIsDisposable = infoIsDisposable;
}
@Override
public void dispose() {
if (infoIsDisposable) {
elements.forEachValue(info -> {
((Disposable)info).dispose();
return true;
});
}
}
private class MyHashMap<K, V> extends THashMap<K, V> {
@Override
protected void removeAt(int index) {
if (infoIsDisposable) {
Disposer.dispose((Disposable)_values[index]);
}
idPool.dispose(((Info)_values[index]).getId());
super.removeAt(index);
}
}
public int add(@NotNull I info) {
assert info.id == -1;
info.id = idPool.allocate();
elements.put(info.element, info);
return info.id;
}
public void remove(@NotNull E element) {
elements.remove(element);
}
public boolean isEmpty() {
return elements.isEmpty();
}
public void forEach(TObjectProcedure<I> procedure) {
elements.forEachValue(procedure);
}
public void remove(int[] ids) {
remove(ids, null);
}
public void remove(int[] ids, @Nullable Consumer<I> removedValueConsumer) {
elements.retainEntries(new RetainCondition<>(ids, removedValueConsumer));
}
public void remove(TObjectObjectProcedure<E, I> filter) {
elements.retainEntries(filter);
}
public boolean contains(E element) {
return elements.containsKey(element);
}
public boolean contains(I info) {
return info.id != -1;
}
@NotNull
public E getElement(int id) {
for (I info : elements.values()) {
if (info.id == id) {
return info.element;
}
}
throw new IllegalArgumentException("Element is not registered for id " + id);
}
@NotNull
public I getInfo(E element) {
return elements.get(element);
}
@Nullable
public I getNullableInfo(E element) {
return elements.get(element);
}
@Nullable
public I getNullableInfo(int id) {
for (I info : elements.values()) {
if (info.id == id) {
return info;
}
}
return null;
}
@NotNull
public I getInfo(int id) {
I result = getNullableInfo(id);
if (result == null) {
throw new IllegalArgumentException("Element is not registered for id " + id);
}
return result;
}
public int getId(E element) {
return getInfo(element).id;
}
public void clear() {
if (infoIsDisposable) {
for (I info : elements.values()) {
Disposer.dispose((Disposable)info);
}
}
elements.clear();
idPool.clear();
}
}