001package net.minecraft.util;
002
003public 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}