001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.jetbrains.kotlin.util.userDataHolder.keyFMap; 017 018 import com.intellij.openapi.util.Key; 019 import org.jetbrains.annotations.NotNull; 020 021 public class ArrayBackedFMap implements KeyFMap { 022 static final int ARRAY_THRESHOLD = 8; 023 private final int[] keys; 024 private final Object[] values; 025 026 ArrayBackedFMap(@NotNull int[] keys, @NotNull Object[] values) { 027 this.keys = keys; 028 this.values = values; 029 } 030 031 @NotNull 032 @Override 033 public <V> KeyFMap plus(@NotNull Key<V> key, @NotNull V value) { 034 int oldSize = size(); 035 int keyCode = key.hashCode(); 036 int[] newKeys = null; 037 Object[] newValues = null; 038 int i; 039 for (i = 0; i < oldSize; i++) { 040 int oldKey = keys[i]; 041 if (keyCode == oldKey) { 042 if (value == values[i]) return this; 043 newKeys = new int[oldSize]; 044 newValues = new Object[oldSize]; 045 System.arraycopy(keys, 0, newKeys, 0, oldSize); 046 System.arraycopy(values, 0, newValues, 0, oldSize); 047 newValues[i] = value; 048 break; 049 } 050 } 051 if (i == oldSize) { 052 if (oldSize == ARRAY_THRESHOLD) { 053 return new MapBackedFMap(keys, keyCode, values, value); 054 } 055 int newSize = oldSize + 1; 056 newKeys = new int[newSize]; 057 newValues = new Object[newSize]; 058 System.arraycopy(keys, 0, newKeys, 0, oldSize); 059 System.arraycopy(values, 0, newValues, 0, oldSize); 060 newKeys[oldSize] = keyCode; 061 newValues[oldSize] = value; 062 } 063 return new ArrayBackedFMap(newKeys, newValues); 064 } 065 066 private int size() { 067 return keys.length; 068 } 069 070 @NotNull 071 @Override 072 public KeyFMap minus(@NotNull Key<?> key) { 073 int oldSize = size(); 074 int keyCode = key.hashCode(); 075 for (int i = 0; i< oldSize; i++) { 076 int oldKey = keys[i]; 077 if (keyCode == oldKey) { 078 if (oldSize == 3) { 079 int i1 = (2-i)/2; 080 int i2 = 3 - (i+2)/2; 081 Key<Object> key1 = Key.getKeyByIndex(keys[i1]); 082 Key<Object> key2 = Key.getKeyByIndex(keys[i2]); 083 if (key1 == null && key2 == null) return EMPTY_MAP; 084 if (key1 == null) return new OneElementFMap<Object>(key2, values[i2]); 085 if (key2 == null) return new OneElementFMap<Object>(key1, values[i1]); 086 return new PairElementsFMap(key1, values[i1], key2, values[i2]); 087 } 088 int newSize = oldSize - 1; 089 int[] newKeys = new int[newSize]; 090 Object[] newValues = new Object[newSize]; 091 System.arraycopy(keys, 0, newKeys, 0, i); 092 System.arraycopy(values, 0, newValues, 0, i); 093 System.arraycopy(keys, i+1, newKeys, i, oldSize-i-1); 094 System.arraycopy(values, i+1, newValues, i, oldSize-i-1); 095 return new ArrayBackedFMap(newKeys, newValues); 096 } 097 } 098 return this; 099 //if (i == oldSize) { 100 //newKeys = new int[oldSize]; 101 //newValues = new Object[oldSize]; 102 //System.arraycopy(keys, 0, newKeys, 0, oldSize); 103 //System.arraycopy(values, 0, newValues, 0, oldSize); 104 //} 105 106 } 107 108 @Override 109 public <V> V get(@NotNull Key<V> key) { 110 int oldSize = size(); 111 int keyCode = key.hashCode(); 112 for (int i = 0; i < oldSize; i++) { 113 int oldKey = keys[i]; 114 if (keyCode == oldKey) { 115 //noinspection unchecked 116 return (V)values[i]; 117 } 118 } 119 return null; 120 } 121 122 @Override 123 public String toString() { 124 String s = ""; 125 for (int i = 0; i < keys.length; i++) { 126 int key = keys[i]; 127 Object value = values[i]; 128 s += (s.isEmpty() ? "" : ", ") + Key.getKeyByIndex(key) + " -> " + value; 129 } 130 return "(" + s + ")"; 131 } 132 133 @Override 134 public boolean isEmpty() { 135 return false; 136 } 137 138 @NotNull 139 public int[] getKeyIds() { 140 return keys; 141 } 142 143 @NotNull 144 @Override 145 public Key[] getKeys() { 146 return getKeysByIndices(keys); 147 } 148 149 @NotNull 150 public Object[] getValues() { 151 return values; 152 } 153 154 @NotNull 155 static Key[] getKeysByIndices(int[] indexes) { 156 Key[] result = new Key[indexes.length]; 157 158 for (int i =0; i < indexes.length; i++) { 159 result[i] = Key.getKeyByIndex(indexes[i]); 160 } 161 162 return result; 163 } 164 }