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 j = getHashedKey(par1);
060
061        for (LongHashMapEntry longhashmapentry = this.hashArray[getHashIndex(j, this.hashArray.length)]; longhashmapentry != null; longhashmapentry = longhashmapentry.nextEntry)
062        {
063            if (longhashmapentry.key == par1)
064            {
065                return longhashmapentry.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 j = getHashedKey(par1);
080
081        for (LongHashMapEntry longhashmapentry = this.hashArray[getHashIndex(j, this.hashArray.length)]; longhashmapentry != null; longhashmapentry = longhashmapentry.nextEntry)
082        {
083            if (longhashmapentry.key == par1)
084            {
085                return longhashmapentry;
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 j = getHashedKey(par1);
098        int k = getHashIndex(j, this.hashArray.length);
099
100        for (LongHashMapEntry longhashmapentry = this.hashArray[k]; longhashmapentry != null; longhashmapentry = longhashmapentry.nextEntry)
101        {
102            if (longhashmapentry.key == par1)
103            {
104                longhashmapentry.value = par3Obj;
105                return;
106            }
107        }
108
109        ++this.modCount;
110        this.createKey(j, par1, par3Obj, k);
111    }
112
113    /**
114     * resizes the table
115     */
116    private void resizeTable(int par1)
117    {
118        LongHashMapEntry[] alonghashmapentry = this.hashArray;
119        int j = alonghashmapentry.length;
120
121        if (j == 1073741824)
122        {
123            this.capacity = Integer.MAX_VALUE;
124        }
125        else
126        {
127            LongHashMapEntry[] alonghashmapentry1 = new LongHashMapEntry[par1];
128            this.copyHashTableTo(alonghashmapentry1);
129            this.hashArray = alonghashmapentry1;
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[] alonghashmapentry1 = this.hashArray;
140        int i = par1ArrayOfLongHashMapEntry.length;
141
142        for (int j = 0; j < alonghashmapentry1.length; ++j)
143        {
144            LongHashMapEntry longhashmapentry = alonghashmapentry1[j];
145
146            if (longhashmapentry != null)
147            {
148                alonghashmapentry1[j] = null;
149                LongHashMapEntry longhashmapentry1;
150
151                do
152                {
153                    longhashmapentry1 = longhashmapentry.nextEntry;
154                    int k = getHashIndex(longhashmapentry.hash, i);
155                    longhashmapentry.nextEntry = par1ArrayOfLongHashMapEntry[k];
156                    par1ArrayOfLongHashMapEntry[k] = longhashmapentry;
157                    longhashmapentry = longhashmapentry1;
158                }
159                while (longhashmapentry1 != 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 longhashmapentry = this.removeKey(par1);
170        return longhashmapentry == null ? null : longhashmapentry.value;
171    }
172
173    /**
174     * removes the key from the hash linked list
175     */
176    final LongHashMapEntry removeKey(long par1)
177    {
178        int j = getHashedKey(par1);
179        int k = getHashIndex(j, this.hashArray.length);
180        LongHashMapEntry longhashmapentry = this.hashArray[k];
181        LongHashMapEntry longhashmapentry1;
182        LongHashMapEntry longhashmapentry2;
183
184        for (longhashmapentry1 = longhashmapentry; longhashmapentry1 != null; longhashmapentry1 = longhashmapentry2)
185        {
186            longhashmapentry2 = longhashmapentry1.nextEntry;
187
188            if (longhashmapentry1.key == par1)
189            {
190                ++this.modCount;
191                --this.numHashElements;
192
193                if (longhashmapentry == longhashmapentry1)
194                {
195                    this.hashArray[k] = longhashmapentry2;
196                }
197                else
198                {
199                    longhashmapentry.nextEntry = longhashmapentry2;
200                }
201
202                return longhashmapentry1;
203            }
204
205            longhashmapentry = longhashmapentry1;
206        }
207
208        return longhashmapentry1;
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 longhashmapentry = this.hashArray[par5];
217        this.hashArray[par5] = new LongHashMapEntry(par1, par2, par4Obj, longhashmapentry);
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}