001    package net.minecraft.util;
002    
003    public class LongHashMap
004    {
005        /** the array of all elements in the hash */
006        private transient LongHashMapEntry[] hashArray = new LongHashMapEntry[16];
007    
008        /** the number of elements in the hash array */
009        private transient int numHashElements;
010    
011        /**
012         * the maximum amount of elements in the hash (probably 3/4 the size due to meh hashing function)
013         */
014        private int capacity = 12;
015    
016        /**
017         * percent of the hasharray that can be used without hash colliding probably
018         */
019        private final float percentUseable = 0.75F;
020    
021        /** count of times elements have been added/removed */
022        private transient volatile int modCount;
023    
024        /**
025         * returns the hashed key given the original key
026         */
027        private static int getHashedKey(long par0)
028        {
029            return hash((int)(par0 ^ par0 >>> 32));
030        }
031    
032        /**
033         * the hash function
034         */
035        private static int hash(int par0)
036        {
037            par0 ^= par0 >>> 20 ^ par0 >>> 12;
038            return par0 ^ par0 >>> 7 ^ par0 >>> 4;
039        }
040    
041        /**
042         * gets the index in the hash given the array length and the hashed key
043         */
044        private static int getHashIndex(int par0, int par1)
045        {
046            return par0 & par1 - 1;
047        }
048    
049        public int getNumHashElements()
050        {
051            return this.numHashElements;
052        }
053    
054        /**
055         * get the value from the map given the key
056         */
057        public Object getValueByKey(long par1)
058        {
059            int var3 = getHashedKey(par1);
060    
061            for (LongHashMapEntry var4 = this.hashArray[getHashIndex(var3, this.hashArray.length)]; var4 != null; var4 = var4.nextEntry)
062            {
063                if (var4.key == par1)
064                {
065                    return var4.value;
066                }
067            }
068    
069            return null;
070        }
071    
072        public boolean containsItem(long par1)
073        {
074            return this.getEntry(par1) != null;
075        }
076    
077        final LongHashMapEntry getEntry(long par1)
078        {
079            int var3 = getHashedKey(par1);
080    
081            for (LongHashMapEntry var4 = this.hashArray[getHashIndex(var3, this.hashArray.length)]; var4 != null; var4 = var4.nextEntry)
082            {
083                if (var4.key == par1)
084                {
085                    return var4;
086                }
087            }
088    
089            return null;
090        }
091    
092        /**
093         * Add a key-value pair.
094         */
095        public void add(long par1, Object par3Obj)
096        {
097            int var4 = getHashedKey(par1);
098            int var5 = getHashIndex(var4, this.hashArray.length);
099    
100            for (LongHashMapEntry var6 = this.hashArray[var5]; var6 != null; var6 = var6.nextEntry)
101            {
102                if (var6.key == par1)
103                {
104                    var6.value = par3Obj;
105                    return;
106                }
107            }
108    
109            ++this.modCount;
110            this.createKey(var4, par1, par3Obj, var5);
111        }
112    
113        /**
114         * resizes the table
115         */
116        private void resizeTable(int par1)
117        {
118            LongHashMapEntry[] var2 = this.hashArray;
119            int var3 = var2.length;
120    
121            if (var3 == 1073741824)
122            {
123                this.capacity = Integer.MAX_VALUE;
124            }
125            else
126            {
127                LongHashMapEntry[] var4 = new LongHashMapEntry[par1];
128                this.copyHashTableTo(var4);
129                this.hashArray = var4;
130                this.capacity = (int)((float)par1 * this.percentUseable);
131            }
132        }
133    
134        /**
135         * copies the hash table to the specified array
136         */
137        private void copyHashTableTo(LongHashMapEntry[] par1ArrayOfLongHashMapEntry)
138        {
139            LongHashMapEntry[] var2 = this.hashArray;
140            int var3 = par1ArrayOfLongHashMapEntry.length;
141    
142            for (int var4 = 0; var4 < var2.length; ++var4)
143            {
144                LongHashMapEntry var5 = var2[var4];
145    
146                if (var5 != null)
147                {
148                    var2[var4] = null;
149                    LongHashMapEntry var6;
150    
151                    do
152                    {
153                        var6 = var5.nextEntry;
154                        int var7 = getHashIndex(var5.hash, var3);
155                        var5.nextEntry = par1ArrayOfLongHashMapEntry[var7];
156                        par1ArrayOfLongHashMapEntry[var7] = var5;
157                        var5 = var6;
158                    }
159                    while (var6 != null);
160                }
161            }
162        }
163    
164        /**
165         * calls the removeKey method and returns removed object
166         */
167        public Object remove(long par1)
168        {
169            LongHashMapEntry var3 = this.removeKey(par1);
170            return var3 == null ? null : var3.value;
171        }
172    
173        /**
174         * removes the key from the hash linked list
175         */
176        final LongHashMapEntry removeKey(long par1)
177        {
178            int var3 = getHashedKey(par1);
179            int var4 = getHashIndex(var3, this.hashArray.length);
180            LongHashMapEntry var5 = this.hashArray[var4];
181            LongHashMapEntry var6;
182            LongHashMapEntry var7;
183    
184            for (var6 = var5; var6 != null; var6 = var7)
185            {
186                var7 = var6.nextEntry;
187    
188                if (var6.key == par1)
189                {
190                    ++this.modCount;
191                    --this.numHashElements;
192    
193                    if (var5 == var6)
194                    {
195                        this.hashArray[var4] = var7;
196                    }
197                    else
198                    {
199                        var5.nextEntry = var7;
200                    }
201    
202                    return var6;
203                }
204    
205                var5 = var6;
206            }
207    
208            return var6;
209        }
210    
211        /**
212         * creates the key in the hash table
213         */
214        private void createKey(int par1, long par2, Object par4Obj, int par5)
215        {
216            LongHashMapEntry var6 = this.hashArray[par5];
217            this.hashArray[par5] = new LongHashMapEntry(par1, par2, par4Obj, var6);
218    
219            if (this.numHashElements++ >= this.capacity)
220            {
221                this.resizeTable(2 * this.hashArray.length);
222            }
223        }
224    
225        /**
226         * public method to get the hashed key(hashCode)
227         */
228        static int getHashCode(long par0)
229        {
230            return getHashedKey(par0);
231        }
232    }