| /* |
| * 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 org.jetbrains.annotations.NotNull; |
| |
| class ArrayBackedFMap implements KeyFMap { |
| static final int ARRAY_THRESHOLD = 8; |
| private final int[] keys; |
| private final Object[] values; |
| |
| ArrayBackedFMap(@NotNull int[] keys, @NotNull Object[] values) { |
| this.keys = keys; |
| this.values = values; |
| } |
| |
| @NotNull |
| @Override |
| public <V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value) { |
| int oldSize = size(); |
| int keyCode = key.hashCode(); |
| int[] newKeys = null; |
| Object[] newValues = null; |
| int i; |
| for (i = 0; i < oldSize; i++) { |
| int oldKey = keys[i]; |
| if (keyCode == oldKey) { |
| if (value == values[i]) return this; |
| newKeys = new int[oldSize]; |
| newValues = new Object[oldSize]; |
| System.arraycopy(keys, 0, newKeys, 0, oldSize); |
| System.arraycopy(values, 0, newValues, 0, oldSize); |
| newValues[i] = value; |
| break; |
| } |
| } |
| if (i == oldSize) { |
| if (oldSize == ARRAY_THRESHOLD) { |
| return new MapBackedFMap(keys, keyCode, values, value); |
| } |
| int newSize = oldSize + 1; |
| newKeys = new int[newSize]; |
| newValues = new Object[newSize]; |
| System.arraycopy(keys, 0, newKeys, 0, oldSize); |
| System.arraycopy(values, 0, newValues, 0, oldSize); |
| newKeys[oldSize] = keyCode; |
| newValues[oldSize] = value; |
| } |
| return new ArrayBackedFMap(newKeys, newValues); |
| } |
| |
| private int size() { |
| return keys.length; |
| } |
| |
| @NotNull |
| @Override |
| public KeyFMap minus(@NotNull Key<?> key) { |
| int oldSize = size(); |
| int keyCode = key.hashCode(); |
| for (int i = 0; i< oldSize; i++) { |
| int oldKey = keys[i]; |
| if (keyCode == oldKey) { |
| if (oldSize == 3) { |
| int i1 = (2-i)/2; |
| int i2 = 3 - (i+2)/2; |
| return new PairElementsFMap(Key.getKeyByIndex(keys[i1]), values[i1], Key.getKeyByIndex(keys[i2]), values[i2]); |
| } |
| int newSize = oldSize - 1; |
| int[] newKeys = new int[newSize]; |
| Object[] newValues = new Object[newSize]; |
| System.arraycopy(keys, 0, newKeys, 0, i); |
| System.arraycopy(values, 0, newValues, 0, i); |
| System.arraycopy(keys, i+1, newKeys, i, oldSize-i-1); |
| System.arraycopy(values, i+1, newValues, i, oldSize-i-1); |
| return new ArrayBackedFMap(newKeys, newValues); |
| } |
| } |
| return this; |
| //if (i == oldSize) { |
| //newKeys = new int[oldSize]; |
| //newValues = new Object[oldSize]; |
| //System.arraycopy(keys, 0, newKeys, 0, oldSize); |
| //System.arraycopy(values, 0, newValues, 0, oldSize); |
| //} |
| |
| } |
| |
| @Override |
| public <V> V get(@NotNull Key<V> key) { |
| int oldSize = size(); |
| int keyCode = key.hashCode(); |
| for (int i = 0; i < oldSize; i++) { |
| int oldKey = keys[i]; |
| if (keyCode == oldKey) { |
| //noinspection unchecked |
| return (V)values[i]; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public String toString() { |
| String s = ""; |
| for (int i = 0; i < keys.length; i++) { |
| int key = keys[i]; |
| Object value = values[i]; |
| s += (s.isEmpty() ? "" : ", ") + Key.getKeyByIndex(key) + " -> " + value; |
| } |
| return "(" + s + ")"; |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return false; |
| } |
| } |