OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2014, the Dart project authors. |
| 3 * |
| 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except |
| 5 * in compliance with the License. You may obtain a copy of the License at |
| 6 * |
| 7 * http://www.eclipse.org/legal/epl-v10.html |
| 8 * |
| 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
| 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
| 11 * or implied. See the License for the specific language governing permissions a
nd limitations under |
| 12 * the License. |
| 13 */ |
| 14 package com.google.dart.engine.internal.index.file; |
| 15 |
| 16 import java.util.Arrays; |
| 17 |
| 18 /** |
| 19 * A hash map with {@code int[]} keys and {@code int} values. |
| 20 * |
| 21 * @coverage dart.engine.index |
| 22 */ |
| 23 public class IntArrayToIntMap { |
| 24 private static class Entry { |
| 25 private final int[] key; |
| 26 private int value; |
| 27 Entry next; |
| 28 |
| 29 public Entry(int[] key, int value, Entry next) { |
| 30 this.key = key; |
| 31 this.value = value; |
| 32 this.next = next; |
| 33 } |
| 34 } |
| 35 |
| 36 private final float loadFactor; |
| 37 private int capacity; |
| 38 private int threshold; |
| 39 private int size; |
| 40 private int[][] keys; |
| 41 private int[] values; |
| 42 private Entry[] entries; |
| 43 |
| 44 public IntArrayToIntMap(int initialCapacity, float loadFactor) { |
| 45 this.loadFactor = loadFactor; |
| 46 capacity = initialCapacity; |
| 47 threshold = (int) (capacity * loadFactor); |
| 48 size = 0; |
| 49 keys = new int[capacity][]; |
| 50 values = new int[capacity]; |
| 51 entries = new Entry[capacity]; |
| 52 } |
| 53 |
| 54 /** |
| 55 * Returns the value to which the specified key is mapped, or the given defaul
t value if this map |
| 56 * contains no mapping for the key. |
| 57 * |
| 58 * @param key the key whose associated value is to be returned |
| 59 * @param defaultValue the default value to to returned if there is no value a
ssociated with the |
| 60 * given key |
| 61 * @return the value associated with {@code key}, or {@code defaultValue} if t
here is no mapping |
| 62 * for {@code key} |
| 63 */ |
| 64 public int get(int[] key, int defaultValue) { |
| 65 int hash = hash(key); |
| 66 int index = hash % capacity; |
| 67 // try "intKeys" |
| 68 { |
| 69 int[] intKey = keys[index]; |
| 70 if (intKey != null && Arrays.equals(intKey, key)) { |
| 71 return values[index]; |
| 72 } |
| 73 } |
| 74 // try "entries" |
| 75 { |
| 76 Entry entry = entries[index]; |
| 77 while (entry != null) { |
| 78 if (Arrays.equals(entry.key, key)) { |
| 79 return entry.value; |
| 80 } |
| 81 entry = entry.next; |
| 82 } |
| 83 } |
| 84 // not found |
| 85 return defaultValue; |
| 86 } |
| 87 |
| 88 /** |
| 89 * Associates the specified value with the specified key in this map. |
| 90 */ |
| 91 public void put(int[] key, int value) { |
| 92 if (size >= threshold) { |
| 93 rehash(); |
| 94 } |
| 95 // prepare hash |
| 96 int hash = hash(key); |
| 97 int index = hash % capacity; |
| 98 // try "keys" |
| 99 Entry entry = entries[index]; |
| 100 if (entry == null) { |
| 101 int[] existingKey = keys[index]; |
| 102 if (existingKey == null) { |
| 103 keys[index] = key; |
| 104 values[index] = value; |
| 105 size++; |
| 106 return; |
| 107 } |
| 108 if (Arrays.equals(existingKey, key)) { |
| 109 values[index] = value; |
| 110 return; |
| 111 } |
| 112 // collision, create new Entry |
| 113 Entry existingEntry = new Entry(existingKey, values[index], null); |
| 114 keys[index] = null; |
| 115 entries[index] = new Entry(key, value, existingEntry); |
| 116 size++; |
| 117 return; |
| 118 } |
| 119 // check existing entries |
| 120 while (entry != null) { |
| 121 if (Arrays.equals(entry.key, key)) { |
| 122 entry.value = value; |
| 123 return; |
| 124 } |
| 125 entry = entry.next; |
| 126 } |
| 127 // add new Entry |
| 128 entries[index] = new Entry(key, value, entries[index]); |
| 129 size++; |
| 130 } |
| 131 |
| 132 /** |
| 133 * Removes the mapping for a key from this map if it is present. |
| 134 * |
| 135 * @param key the key whose mapping is to be removed from the map |
| 136 * @param defaultValue the default value to to returned if there is no value a
ssociated with the |
| 137 * given key |
| 138 * @return the previous value associated with {@code key}, or {@code defaultVa
lue} if there was no |
| 139 * mapping for {@code key} |
| 140 */ |
| 141 public int remove(int[] key, int defaultValue) { |
| 142 int hash = hash(key); |
| 143 int index = hash % capacity; |
| 144 // try "keys" |
| 145 { |
| 146 int[] existingKey = keys[index]; |
| 147 if (existingKey != null && Arrays.equals(existingKey, key)) { |
| 148 size--; |
| 149 keys[index] = null; |
| 150 return values[index]; |
| 151 } |
| 152 } |
| 153 // try "entries" |
| 154 { |
| 155 Entry entry = entries[index]; |
| 156 Entry prev = null; |
| 157 while (entry != null) { |
| 158 if (Arrays.equals(entry.key, key)) { |
| 159 size--; |
| 160 int value = entry.value; |
| 161 if (entries[index] == entry) { |
| 162 entries[index] = entry.next; |
| 163 } else { |
| 164 prev.next = entry.next; |
| 165 } |
| 166 return value; |
| 167 } |
| 168 prev = entry; |
| 169 entry = entry.next; |
| 170 } |
| 171 } |
| 172 // not found |
| 173 return defaultValue; |
| 174 } |
| 175 |
| 176 /** |
| 177 * Returns the number of key-value mappings in this map. |
| 178 */ |
| 179 public int size() { |
| 180 return size; |
| 181 } |
| 182 |
| 183 private int hash(int[] key) { |
| 184 int result = 1; |
| 185 for (int element : key) { |
| 186 result = 31 * result + element; |
| 187 } |
| 188 return result & 0x7FFFFFFF; |
| 189 } |
| 190 |
| 191 private void rehash() { |
| 192 IntArrayToIntMap newMap = new IntArrayToIntMap(capacity * 2 + 1, loadFactor)
; |
| 193 // put values |
| 194 for (int i = 0; i < keys.length; i++) { |
| 195 int[] key = keys[i]; |
| 196 if (key != null) { |
| 197 newMap.put(key, values[i]); |
| 198 } |
| 199 } |
| 200 for (int i = 0; i < entries.length; i++) { |
| 201 Entry entry = entries[i]; |
| 202 while (entry != null) { |
| 203 newMap.put(entry.key, entry.value); |
| 204 entry = entry.next; |
| 205 } |
| 206 } |
| 207 // copy data |
| 208 capacity = newMap.capacity; |
| 209 threshold = newMap.threshold; |
| 210 keys = newMap.keys; |
| 211 values = newMap.values; |
| 212 entries = newMap.entries; |
| 213 } |
| 214 } |
OLD | NEW |