    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    }