001package net.minecraft.util; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.HashSet; 006import java.util.Set; 007 008public class IntHashMap 009{ 010 /** An array of HashEntries representing the heads of hash slot lists */ 011 private transient IntHashMapEntry[] slots = new IntHashMapEntry[16]; 012 013 /** The number of items stored in this map */ 014 private transient int count; 015 016 /** The grow threshold */ 017 private int threshold = 12; 018 019 /** The scale factor used to determine when to grow the table */ 020 private final float growFactor = 0.75F; 021 022 /** A serial stamp used to mark changes */ 023 private transient volatile int versionStamp; 024 025 /** The set of all the keys stored in this MCHash object */ 026 private Set keySet = new HashSet(); 027 028 /** 029 * Makes the passed in integer suitable for hashing by a number of shifts 030 */ 031 private static int computeHash(int par0) 032 { 033 par0 ^= par0 >>> 20 ^ par0 >>> 12; 034 return par0 ^ par0 >>> 7 ^ par0 >>> 4; 035 } 036 037 /** 038 * Computes the index of the slot for the hash and slot count passed in. 039 */ 040 private static int getSlotIndex(int par0, int par1) 041 { 042 return par0 & par1 - 1; 043 } 044 045 /** 046 * Returns the object associated to a key 047 */ 048 public Object lookup(int par1) 049 { 050 int j = computeHash(par1); 051 052 for (IntHashMapEntry inthashmapentry = this.slots[getSlotIndex(j, this.slots.length)]; inthashmapentry != null; inthashmapentry = inthashmapentry.nextEntry) 053 { 054 if (inthashmapentry.hashEntry == par1) 055 { 056 return inthashmapentry.valueEntry; 057 } 058 } 059 060 return null; 061 } 062 063 /** 064 * Return true if an object is associated with the given key 065 */ 066 public boolean containsItem(int par1) 067 { 068 return this.lookupEntry(par1) != null; 069 } 070 071 /** 072 * Returns the key/object mapping for a given key as a MCHashEntry 073 */ 074 final IntHashMapEntry lookupEntry(int par1) 075 { 076 int j = computeHash(par1); 077 078 for (IntHashMapEntry inthashmapentry = this.slots[getSlotIndex(j, this.slots.length)]; inthashmapentry != null; inthashmapentry = inthashmapentry.nextEntry) 079 { 080 if (inthashmapentry.hashEntry == par1) 081 { 082 return inthashmapentry; 083 } 084 } 085 086 return null; 087 } 088 089 /** 090 * Adds a key and associated value to this map 091 */ 092 public void addKey(int par1, Object par2Obj) 093 { 094 this.keySet.add(Integer.valueOf(par1)); 095 int j = computeHash(par1); 096 int k = getSlotIndex(j, this.slots.length); 097 098 for (IntHashMapEntry inthashmapentry = this.slots[k]; inthashmapentry != null; inthashmapentry = inthashmapentry.nextEntry) 099 { 100 if (inthashmapentry.hashEntry == par1) 101 { 102 inthashmapentry.valueEntry = par2Obj; 103 return; 104 } 105 } 106 107 ++this.versionStamp; 108 this.insert(j, par1, par2Obj, k); 109 } 110 111 /** 112 * Increases the number of hash slots 113 */ 114 private void grow(int par1) 115 { 116 IntHashMapEntry[] ainthashmapentry = this.slots; 117 int j = ainthashmapentry.length; 118 119 if (j == 1073741824) 120 { 121 this.threshold = Integer.MAX_VALUE; 122 } 123 else 124 { 125 IntHashMapEntry[] ainthashmapentry1 = new IntHashMapEntry[par1]; 126 this.copyTo(ainthashmapentry1); 127 this.slots = ainthashmapentry1; 128 this.threshold = (int)((float)par1 * this.growFactor); 129 } 130 } 131 132 /** 133 * Copies the hash slots to a new array 134 */ 135 private void copyTo(IntHashMapEntry[] par1ArrayOfIntHashMapEntry) 136 { 137 IntHashMapEntry[] ainthashmapentry1 = this.slots; 138 int i = par1ArrayOfIntHashMapEntry.length; 139 140 for (int j = 0; j < ainthashmapentry1.length; ++j) 141 { 142 IntHashMapEntry inthashmapentry = ainthashmapentry1[j]; 143 144 if (inthashmapentry != null) 145 { 146 ainthashmapentry1[j] = null; 147 IntHashMapEntry inthashmapentry1; 148 149 do 150 { 151 inthashmapentry1 = inthashmapentry.nextEntry; 152 int k = getSlotIndex(inthashmapentry.slotHash, i); 153 inthashmapentry.nextEntry = par1ArrayOfIntHashMapEntry[k]; 154 par1ArrayOfIntHashMapEntry[k] = inthashmapentry; 155 inthashmapentry = inthashmapentry1; 156 } 157 while (inthashmapentry1 != null); 158 } 159 } 160 } 161 162 /** 163 * Removes the specified object from the map and returns it 164 */ 165 public Object removeObject(int par1) 166 { 167 this.keySet.remove(Integer.valueOf(par1)); 168 IntHashMapEntry inthashmapentry = this.removeEntry(par1); 169 return inthashmapentry == null ? null : inthashmapentry.valueEntry; 170 } 171 172 /** 173 * Removes the specified entry from the map and returns it 174 */ 175 final IntHashMapEntry removeEntry(int par1) 176 { 177 int j = computeHash(par1); 178 int k = getSlotIndex(j, this.slots.length); 179 IntHashMapEntry inthashmapentry = this.slots[k]; 180 IntHashMapEntry inthashmapentry1; 181 IntHashMapEntry inthashmapentry2; 182 183 for (inthashmapentry1 = inthashmapentry; inthashmapentry1 != null; inthashmapentry1 = inthashmapentry2) 184 { 185 inthashmapentry2 = inthashmapentry1.nextEntry; 186 187 if (inthashmapentry1.hashEntry == par1) 188 { 189 ++this.versionStamp; 190 --this.count; 191 192 if (inthashmapentry == inthashmapentry1) 193 { 194 this.slots[k] = inthashmapentry2; 195 } 196 else 197 { 198 inthashmapentry.nextEntry = inthashmapentry2; 199 } 200 201 return inthashmapentry1; 202 } 203 204 inthashmapentry = inthashmapentry1; 205 } 206 207 return inthashmapentry1; 208 } 209 210 /** 211 * Removes all entries from the map 212 */ 213 public void clearMap() 214 { 215 ++this.versionStamp; 216 IntHashMapEntry[] ainthashmapentry = this.slots; 217 218 for (int i = 0; i < ainthashmapentry.length; ++i) 219 { 220 ainthashmapentry[i] = null; 221 } 222 223 this.count = 0; 224 } 225 226 /** 227 * Adds an object to a slot 228 */ 229 private void insert(int par1, int par2, Object par3Obj, int par4) 230 { 231 IntHashMapEntry inthashmapentry = this.slots[par4]; 232 this.slots[par4] = new IntHashMapEntry(par1, par2, par3Obj, inthashmapentry); 233 234 if (this.count++ >= this.threshold) 235 { 236 this.grow(2 * this.slots.length); 237 } 238 } 239 240 @SideOnly(Side.CLIENT) 241 242 /** 243 * Return the Set of all keys stored in this MCHash object 244 */ 245 public Set getKeySet() 246 { 247 return this.keySet; 248 } 249 250 /** 251 * Returns the hash code for a key 252 */ 253 static int getHash(int par0) 254 { 255 return computeHash(par0); 256 } 257}