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}