    001    package net.minecraft.util;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.SideOnly;
    005    import java.util.HashSet;
    006    import java.util.Set;
    007
    008    public class IntHashMap
    009    {
    010        /** An array of HashEntries representing the heads of hash slot lists */
    011        private transient IntHashMapEntry[] slots = new IntHashMapEntry[16];
    012
    013        /** The number of items stored in this map */
    014        private transient int count;
    015
    016        /** The grow threshold */
    017        private int threshold = 12;
    018
    019        /** The scale factor used to determine when to grow the table */
    020        private final float growFactor = 0.75F;
    021
    022        /** A serial stamp used to mark changes */
    023        private transient volatile int versionStamp;
    024
    025        /** The set of all the keys stored in this MCHash object */
    026        private Set keySet = new HashSet();
    027
    028        /**
    029         * Makes the passed in integer suitable for hashing by a number of shifts
    030         */
    031        private static int computeHash(int par0)
    032        {
    033            par0 ^= par0 >>> 20 ^ par0 >>> 12;
    034            return par0 ^ par0 >>> 7 ^ par0 >>> 4;
    035        }
    036
    037        /**
    038         * Computes the index of the slot for the hash and slot count passed in.
    039         */
    040        private static int getSlotIndex(int par0, int par1)
    041        {
    042            return par0 & par1 - 1;
    043        }
    044
    045        /**
    046         * Returns the object associated to a key
    047         */
    048        public Object lookup(int par1)
    049        {
    050            int var2 = computeHash(par1);
    051
    052            for (IntHashMapEntry var3 = this.slots[getSlotIndex(var2, this.slots.length)]; var3 != null; var3 = var3.nextEntry)
    053            {
    054                if (var3.hashEntry == par1)
    055                {
    056                    return var3.valueEntry;
    057                }
    058            }
    059
    060            return null;
    061        }
    062
    063        /**
    064         * Return true if an object is associated with the given key
    065         */
    066        public boolean containsItem(int par1)
    067        {
    068            return this.lookupEntry(par1) != null;
    069        }
    070
    071        /**
    072         * Returns the key/object mapping for a given key as a MCHashEntry
    073         */
    074        final IntHashMapEntry lookupEntry(int par1)
    075        {
    076            int var2 = computeHash(par1);
    077
    078            for (IntHashMapEntry var3 = this.slots[getSlotIndex(var2, this.slots.length)]; var3 != null; var3 = var3.nextEntry)
    079            {
    080                if (var3.hashEntry == par1)
    081                {
    082                    return var3;
    083                }
    084            }
    085
    086            return null;
    087        }
    088
    089        /**
    090         * Adds a key and associated value to this map
    091         */
    092        public void addKey(int par1, Object par2Obj)
    093        {
    094            this.keySet.add(Integer.valueOf(par1));
    095            int var3 = computeHash(par1);
    096            int var4 = getSlotIndex(var3, this.slots.length);
    097
    098            for (IntHashMapEntry var5 = this.slots[var4]; var5 != null; var5 = var5.nextEntry)
    099            {
    100                if (var5.hashEntry == par1)
    101                {
    102                    var5.valueEntry = par2Obj;
    103                    return;
    104                }
    105            }
    106
    107            ++this.versionStamp;
    108            this.insert(var3, par1, par2Obj, var4);
    109        }
    110
    111        /**
    112         * Increases the number of hash slots
    113         */
    114        private void grow(int par1)
    115        {
    116            IntHashMapEntry[] var2 = this.slots;
    117            int var3 = var2.length;
    118
    119            if (var3 == 1073741824)
    120            {
    121                this.threshold = Integer.MAX_VALUE;
    122            }
    123            else
    124            {
    125                IntHashMapEntry[] var4 = new IntHashMapEntry[par1];
    126                this.copyTo(var4);
    127                this.slots = var4;
    128                this.threshold = (int)((float)par1 * this.growFactor);
    129            }
    130        }
    131
    132        /**
    133         * Copies the hash slots to a new array
    134         */
    135        private void copyTo(IntHashMapEntry[] par1ArrayOfIntHashMapEntry)
    136        {
    137            IntHashMapEntry[] var2 = this.slots;
    138            int var3 = par1ArrayOfIntHashMapEntry.length;
    139
    140            for (int var4 = 0; var4 < var2.length; ++var4)
    141            {
    142                IntHashMapEntry var5 = var2[var4];
    143
    144                if (var5 != null)
    145                {
    146                    var2[var4] = null;
    147                    IntHashMapEntry var6;
    148
    149                    do
    150                    {
    151                        var6 = var5.nextEntry;
    152                        int var7 = getSlotIndex(var5.slotHash, var3);
    153                        var5.nextEntry = par1ArrayOfIntHashMapEntry[var7];
    154                        par1ArrayOfIntHashMapEntry[var7] = var5;
    155                        var5 = var6;
    156                    }
    157                    while (var6 != null);
    158                }
    159            }
    160        }
    161
    162        /**
    163         * Removes the specified object from the map and returns it
    164         */
    165        public Object removeObject(int par1)
    166        {
    167            this.keySet.remove(Integer.valueOf(par1));
    168            IntHashMapEntry var2 = this.removeEntry(par1);
    169            return var2 == null ? null : var2.valueEntry;
    170        }
    171
    172        /**
    173         * Removes the specified entry from the map and returns it
    174         */
    175        final IntHashMapEntry removeEntry(int par1)
    176        {
    177            int var2 = computeHash(par1);
    178            int var3 = getSlotIndex(var2, this.slots.length);
    179            IntHashMapEntry var4 = this.slots[var3];
    180            IntHashMapEntry var5;
    181            IntHashMapEntry var6;
    182
    183            for (var5 = var4; var5 != null; var5 = var6)
    184            {
    185                var6 = var5.nextEntry;
    186
    187                if (var5.hashEntry == par1)
    188                {
    189                    ++this.versionStamp;
    190                    --this.count;
    191
    192                    if (var4 == var5)
    193                    {
    194                        this.slots[var3] = var6;
    195                    }
    196                    else
    197                    {
    198                        var4.nextEntry = var6;
    199                    }
    200
    201                    return var5;
    202                }
    203
    204                var4 = var5;
    205            }
    206
    207            return var5;
    208        }
    209
    210        /**
    211         * Removes all entries from the map
    212         */
    213        public void clearMap()
    214        {
    215            ++this.versionStamp;
    216            IntHashMapEntry[] var1 = this.slots;
    217
    218            for (int var2 = 0; var2 < var1.length; ++var2)
    219            {
    220                var1[var2] = null;
    221            }
    222
    223            this.count = 0;
    224        }
    225
    226        /**
    227         * Adds an object to a slot
    228         */
    229        private void insert(int par1, int par2, Object par3Obj, int par4)
    230        {
    231            IntHashMapEntry var5 = this.slots[par4];
    232            this.slots[par4] = new IntHashMapEntry(par1, par2, par3Obj, var5);
    233
    234            if (this.count++ >= this.threshold)
    235            {
    236                this.grow(2 * this.slots.length);
    237            }
    238        }
    239
    240        @SideOnly(Side.CLIENT)
    241
    242        /**
    243         * Return the Set of all keys stored in this MCHash object
    244         */
    245        public Set getKeySet()
    246        {
    247            return this.keySet;
    248        }
    249
    250        /**
    251         * Returns the hash code for a key
    252         */
    253        static int getHash(int par0)
    254        {
    255            return computeHash(par0);
    256        }
    257    }