001 package net.minecraft.util; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.HashSet; 006 import java.util.Set; 007 008 public 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 var2 = computeHash(par1); 051 052 for (IntHashMapEntry var3 = this.slots[getSlotIndex(var2, this.slots.length)]; var3 != null; var3 = var3.nextEntry) 053 { 054 if (var3.hashEntry == par1) 055 { 056 return var3.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 var2 = computeHash(par1); 077 078 for (IntHashMapEntry var3 = this.slots[getSlotIndex(var2, this.slots.length)]; var3 != null; var3 = var3.nextEntry) 079 { 080 if (var3.hashEntry == par1) 081 { 082 return var3; 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 var3 = computeHash(par1); 096 int var4 = getSlotIndex(var3, this.slots.length); 097 098 for (IntHashMapEntry var5 = this.slots[var4]; var5 != null; var5 = var5.nextEntry) 099 { 100 if (var5.hashEntry == par1) 101 { 102 var5.valueEntry = par2Obj; 103 return; 104 } 105 } 106 107 ++this.versionStamp; 108 this.insert(var3, par1, par2Obj, var4); 109 } 110 111 /** 112 * Increases the number of hash slots 113 */ 114 private void grow(int par1) 115 { 116 IntHashMapEntry[] var2 = this.slots; 117 int var3 = var2.length; 118 119 if (var3 == 1073741824) 120 { 121 this.threshold = Integer.MAX_VALUE; 122 } 123 else 124 { 125 IntHashMapEntry[] var4 = new IntHashMapEntry[par1]; 126 this.copyTo(var4); 127 this.slots = var4; 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[] var2 = this.slots; 138 int var3 = par1ArrayOfIntHashMapEntry.length; 139 140 for (int var4 = 0; var4 < var2.length; ++var4) 141 { 142 IntHashMapEntry var5 = var2[var4]; 143 144 if (var5 != null) 145 { 146 var2[var4] = null; 147 IntHashMapEntry var6; 148 149 do 150 { 151 var6 = var5.nextEntry; 152 int var7 = getSlotIndex(var5.slotHash, var3); 153 var5.nextEntry = par1ArrayOfIntHashMapEntry[var7]; 154 par1ArrayOfIntHashMapEntry[var7] = var5; 155 var5 = var6; 156 } 157 while (var6 != 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 var2 = this.removeEntry(par1); 169 return var2 == null ? null : var2.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 var2 = computeHash(par1); 178 int var3 = getSlotIndex(var2, this.slots.length); 179 IntHashMapEntry var4 = this.slots[var3]; 180 IntHashMapEntry var5; 181 IntHashMapEntry var6; 182 183 for (var5 = var4; var5 != null; var5 = var6) 184 { 185 var6 = var5.nextEntry; 186 187 if (var5.hashEntry == par1) 188 { 189 ++this.versionStamp; 190 --this.count; 191 192 if (var4 == var5) 193 { 194 this.slots[var3] = var6; 195 } 196 else 197 { 198 var4.nextEntry = var6; 199 } 200 201 return var5; 202 } 203 204 var4 = var5; 205 } 206 207 return var5; 208 } 209 210 /** 211 * Removes all entries from the map 212 */ 213 public void clearMap() 214 { 215 ++this.versionStamp; 216 IntHashMapEntry[] var1 = this.slots; 217 218 for (int var2 = 0; var2 < var1.length; ++var2) 219 { 220 var1[var2] = 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 var5 = this.slots[par4]; 232 this.slots[par4] = new IntHashMapEntry(par1, par2, par3Obj, var5); 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 }