    001package net.minecraft.util;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.HashSet;
    006import java.util.Set;
    007
    008public 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}