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    }