blob: 4f9ba3e400bddc2111daa0dc1b2f419db5e437c3 [file] [log] [blame]
/*
* Copyright 2000-2012 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.util.keyFMap;
import com.intellij.openapi.util.Key;
import com.intellij.util.ArrayUtil;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TIntObjectProcedure;
import org.jetbrains.annotations.NotNull;
class MapBackedFMap extends TIntObjectHashMap<Object> implements KeyFMap {
private MapBackedFMap(@NotNull MapBackedFMap oldMap, final int exclude) {
super(oldMap.size());
oldMap.forEachEntry(new TIntObjectProcedure<Object>() {
@Override
public boolean execute(int key, Object val) {
if (key != exclude) put(key, val);
assert key >= 0 : key;
return true;
}
});
assert size() > ArrayBackedFMap.ARRAY_THRESHOLD;
}
MapBackedFMap(@NotNull int[] keys, int newKey, @NotNull Object[] values, @NotNull Object newValue) {
super(keys.length + 1);
for (int i = 0; i < keys.length; i++) {
int key = keys[i];
Object value = values[i];
put(key, value);
assert key >= 0 : key;
}
put(newKey, newValue);
assert newKey >= 0 : newKey;
assert size() > ArrayBackedFMap.ARRAY_THRESHOLD;
}
@NotNull
@Override
public <V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value) {
int keyCode = key.hashCode();
assert keyCode >= 0 : key;
@SuppressWarnings("unchecked")
V oldValue = (V)get(keyCode);
if (value == oldValue) return this;
MapBackedFMap newMap = new MapBackedFMap(this, -1);
newMap.put(keyCode, value);
return newMap;
}
@NotNull
@Override
public KeyFMap minus(@NotNull Key<?> key) {
int oldSize = size();
int keyCode = key.hashCode();
if (!containsKey(keyCode)) {
return this;
}
if (oldSize == ArrayBackedFMap.ARRAY_THRESHOLD + 1) {
int[] keys = keys();
Object[] values = getValues();
int i = ArrayUtil.indexOf(keys, keyCode);
keys = ArrayUtil.remove(keys, i);
values = ArrayUtil.remove(values, i);
return new ArrayBackedFMap(keys, values);
}
return new MapBackedFMap(this, keyCode);
}
@Override
public <V> V get(@NotNull Key<V> key) {
//noinspection unchecked
return (V)get(key.hashCode());
}
@Override
public String toString() {
final StringBuilder s = new StringBuilder();
forEachEntry(new TIntObjectProcedure<Object>() {
@Override
public boolean execute(int key, Object value) {
s.append(s.length() == 0 ? "" : ", ").append(Key.getKeyByIndex(key)).append(" -> ").append(value);
return true;
}
});
return "[" + s.toString() + "]";
}
}