summaryrefslogtreecommitdiff
path: root/platform/analysis-impl/src/com/intellij/codeInspection/SmartHashMap.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/analysis-impl/src/com/intellij/codeInspection/SmartHashMap.java')
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInspection/SmartHashMap.java206
1 files changed, 206 insertions, 0 deletions
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/SmartHashMap.java b/platform/analysis-impl/src/com/intellij/codeInspection/SmartHashMap.java
new file mode 100644
index 000000000000..e66ae1ee379f
--- /dev/null
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/SmartHashMap.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2000-2014 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 com.intellij.codeInspection;
+
+import com.intellij.openapi.util.Comparing;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.SingletonSet;
+import gnu.trove.THashMap;
+import gnu.trove.TObjectFunction;
+import gnu.trove.TObjectObjectProcedure;
+import gnu.trove.TObjectProcedure;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Hash set (based on THashSet) which is fast when contains one or zero elements (avoids to calculate hash codes and call equals whenever possible).
+ * For other sizes it delegates to THashSet.
+ * Null keys are NOT PERMITTED.
+ */
+public class SmartHashMap<K,V> extends THashMap<K,V> {
+ private K theKey; // contains the only element if size() == 1
+ private V theValue;
+
+ @Override
+ public boolean containsKey(@NotNull Object key) {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return eq(theKey, (K)key);
+ }
+ return !super.isEmpty() && super.containsKey(key);
+ }
+
+ @Override
+ public V put(@NotNull K key, V value) {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ if (eq(theKey, key)) return theValue;
+ super.put(theKey, theValue);
+ this.theKey = null;
+ // fallthrough
+ }
+ else if (super.isEmpty()) {
+ this.theKey = key;
+ theValue = value;
+ return null;
+ }
+ return super.put(key, value);
+ }
+
+ private boolean eq(K obj, K theKey) {
+ return theKey == obj || _hashingStrategy.equals(theKey, obj);
+ }
+
+ @Override
+ public boolean equals(@NotNull Object other) {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ if (!(other instanceof Map) || ((Map)other).size() != 1 ) return false;
+ Map.Entry<K, V> entry = ((Map<K, V>)other).entrySet().iterator().next();
+ return eq(theKey, entry.getKey()) && Comparing.equal(theValue, entry.getValue());
+ }
+
+ return super.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return _hashingStrategy.computeHashCode(theKey);
+ }
+ return super.hashCode();
+ }
+
+ @Override
+ public void clear() {
+ theKey = null;
+ theValue = null;
+ super.clear();
+ }
+
+ @Override
+ public int size() {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return 1;
+ }
+ return super.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ K theKey = this.theKey;
+ return theKey == null && super.isEmpty();
+ }
+
+ @Override
+ public V remove(@NotNull Object obj) {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ if (eq(theKey, (K)obj)) {
+ this.theKey = null;
+ V value = theValue;
+ theValue = null;
+ return value;
+ }
+ return null;
+ }
+ return super.remove(obj);
+ }
+
+ @NotNull
+ @Override
+ public Set<K> keySet() {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return new SingletonSet<K>(theKey);
+ }
+ return super.keySet();
+ }
+
+ @NotNull
+ @Override
+ public Collection<V> values() {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return new SingletonSet<V>(theValue);
+ }
+ return super.values();
+ }
+
+ @NotNull
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return new SingletonSet<Map.Entry<K, V>>(new AbstractMap.SimpleEntry<K, V>(theKey, theValue));
+ }
+ return super.entrySet();
+ }
+
+ @Override
+ public V get(Object key) {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return eq(theKey, (K)key) ? theValue : null;
+ }
+ return super.get(key);
+ }
+
+ @Override
+ public boolean containsValue(Object val) {
+ K theKey = this.theKey;
+ if (theKey != null) {
+ return Comparing.equal(theValue, val);
+ }
+ return super.containsValue(val);
+ }
+
+ @Override
+ public THashMap<K, V> clone() {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public void transformValues(TObjectFunction<V, V> function) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public boolean retainEntries(TObjectObjectProcedure<K, V> procedure) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public boolean forEachEntry(TObjectObjectProcedure<K, V> procedure) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public boolean forEachValue(TObjectProcedure<V> procedure) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public boolean forEachKey(TObjectProcedure<K> procedure) {
+ throw new IncorrectOperationException();
+ }
+}