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 }