    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}