/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.util;
import jpcsp.memory.IMemoryReader;
import jpcsp.memory.MemoryReader;
public class Hash {
// 256 Random values
private static final int[] salt = {
0x3A5601D2, 0x2B3DCB11, 0xEA39A63C, 0x552CBCBF,
0xEDBAFEB2, 0xD9681D5E, 0x6BCE43BC, 0xF35B9D44,
0x13D021E5, 0x57967C85, 0xECD08AB0, 0x0668A455,
0x2C57D2BC, 0x51CC3E09, 0x1D398CA5, 0xF4F67487,
0xD0492F70, 0xF2815B60, 0x427E687E, 0x333E8EED,
0x837A4C56, 0x78D8131E, 0x205C3ECD, 0xB4DBD2E2,
0xD752B250, 0x8728F852, 0x287E9763, 0xB256B605,
0x9D82D087, 0x75361430, 0xA5AE0C29, 0x4CEE7885,
0x90545556, 0xC33BFDEF, 0xD3BE4D31, 0xB10AD99E,
0x06F2A289, 0x2D220CF4, 0xC94FD207, 0xF4761062,
0xF649D0C6, 0x2D790930, 0x64EACC4D, 0x39370CBC,
0x460DF64B, 0x0109FDC5, 0x893E2F86, 0x04E044B1,
0xFC63A4D9, 0x53AD11EF, 0x65A6E231, 0x2EA791E9,
0xBCBDD2EF, 0xB83A8C21, 0x2DD06C1A, 0xF8DFE36E,
0xCF14A43B, 0x55E6636E, 0xEE81B5EB, 0x94B5C7B2,
0x4EDBC54D, 0xDF79032A, 0x63BDAE09, 0x6D9C12D6,
0x24564E8D, 0xEADE24D1, 0x2E88E69D, 0xACE62529,
0x2251626F, 0x33ACE426, 0x342280F0, 0xB1E195EE,
0x9D2DFAE4, 0xB7DA719F, 0x8E8FF9FB, 0x07994661,
0x51B59A13, 0x14FB0700, 0x5C40AC3E, 0x3B8820FC,
0xB1BCD248, 0x1C8B0245, 0x13871AD0, 0xF02208F6,
0x1551D92C, 0x68F44AC4, 0x43F359B7, 0x6F7DBE0B,
0xC0649A36, 0x61A26493, 0xF47B2779, 0xB5D2B882,
0xB9B8FC61, 0xC4B9D626, 0xF7118BF2, 0x852A416C,
0x9FCB4F1F, 0x8F2DC43D, 0x92191068, 0x33D34B29,
0xB65A128D, 0x3238E7FC, 0x1338E4DC, 0xF21CCE30,
0x82C78EE7, 0x0DED435B, 0x1ECE86A2, 0xA1D2AE0E,
0x59B8EF3D, 0x65E037C0, 0x90BABC33, 0xB7356AAE,
0x147FD366, 0x9D2EE2E9, 0x4FE1FA42, 0x27E521DB,
0xCC368D35, 0xC470E60F, 0xAAA5860C, 0x1CBCA503,
0x72467CEB, 0x14EDFB48, 0x611BE8F4, 0xE821A73E,
0x9D9340EB, 0x2ACCFD2C, 0xEF24894E, 0xE71B478D,
0x0FFCACB4, 0xE23944BB, 0x8DDB7C7A, 0x30D07B66,
0xAC94BB0A, 0x03E5817E, 0xAEAFE635, 0xD2241D70,
0xA305EF76, 0x2A216FEB, 0xE3B0792B, 0x523CA48A,
0xFB79DAF1, 0xDB2A120D, 0x95C6ECCF, 0x2D21C711,
0xE716B7DB, 0x05B24E64, 0xFBD47C6F, 0x237A8E62,
0xEF265132, 0x441C1909, 0x3A2EC382, 0xC61A9E9D,
0x6F67A8FF, 0x57B88B15, 0xBA1D8B44, 0x99B5B6AC,
0x8A301213, 0xA1E78C43, 0xC9EF5D84, 0xEEFCAC83,
0xBE17B0F3, 0x5355F2D4, 0xA943F0BC, 0xF5D769A8,
0x70389810, 0x14233DB2, 0xD788C162, 0x4BA3ABF6,
0x8AC6F33B, 0xE8A64CD8, 0xED956C7D, 0xF4988E9D,
0xE13BF657, 0x901ABBF0, 0x741A9F7A, 0x43EB1F6C,
0x78B4834F, 0xF2F6C33D, 0x106FB13F, 0x1D508452,
0x67BFBB4A, 0xF843C2BB, 0x65783880, 0x693E7521,
0x7BE8EF1D, 0x3251DB84, 0x181C3352, 0xC4130D95,
0xA80BA301, 0xD5C13B74, 0x4B6293FD, 0xDB593B95,
0xD4379985, 0xD061FF10, 0x78E74715, 0x93EF4DB8,
0x99D619C5, 0x3215CDA3, 0xF46306CB, 0xBC29660A,
0xD420E4DC, 0x6EEC93A9, 0x6D8C8F80, 0x7E61D50F,
0x790E8E96, 0xF167FF71, 0xF800099B, 0x0F05A107,
0xA0DF2D6A, 0x8467A3FD, 0x2E52BC9B, 0xBD4BBD73,
0xE5AF95A7, 0xF7F9E62C, 0xE9465F6F, 0xF3A9B6D7,
0xB82893EC, 0x196C181A, 0x4F709A04, 0x2D00D6C2,
0xFDC2DADC, 0x57B666C7, 0x19E08C20, 0x09AB040B,
0x4F6F9812, 0xD0067DF6, 0x48956D6E, 0xA43EE35C,
0xB800E453, 0xBCF60657, 0xF3369AD9, 0xED56FBF4,
0x8FAC8302, 0x7C2861E7, 0xC8AEA51C, 0x181FE4A8,
0x68B6A4D8, 0x53DD4A97, 0x6050349A, 0x2B2DBD2A,
0x47F9A1D3, 0x7ABC372B, 0x0244D66A, 0x4A59778D,
0x25DADE6F, 0x69F6AA65, 0xA07306B6, 0xBB6AB608,
0xF08C5013, 0x631DD062, 0x8E0A0C45, 0x785B40F9,
0xB27D54CE, 0x21EA0E43, 0x1FB77955, 0x134D592D
};
/**
* Generate a hashCode on a memory range using a rather simple but fast method.
*
* @param hashCode current hashCode value
* @param addr start of the memory range to be hashed
* @param lengthInBytes length of the memory range
* @return updated hashCode value
*/
public static int getHashCode(int hashCode, int addr, int lengthInBytes) {
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, lengthInBytes, 4);
for (int i = 0, j = 0; i < lengthInBytes; i += 4, j++) {
int value = memoryReader.readNext();
hashCode ^= value + salt[j & 0xFF];
hashCode += i + addr;
}
return hashCode;
}
/**
* Generate a hashCode on a memory range using a rather simple but fast method
* and a stride.
*
* @param hashCode current hashCode value
* @param addr start of the memory range to be hashed
* @param lengthInBytes length of the memory range
* @param strideInBytes stride (hash only 4 bytes every stride bytes)
* @return updated hashCode value
*/
public static int getHashCode(int hashCode, int addr, int lengthInBytes, int strideInBytes) {
if (strideInBytes <= 4) {
// There is no stride...
return getHashCode(hashCode, addr, lengthInBytes);
}
int skip = (strideInBytes / 4) - 1;
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, lengthInBytes, 4);
int step = (skip + 1) * 4;
lengthInBytes -= lengthInBytes % strideInBytes;
for (int i = 0, j = 0; i < lengthInBytes; i += step, j++) {
int value = memoryReader.readNext();
memoryReader.skip(skip);
hashCode ^= value + salt[j & 0xFF];
hashCode += i + addr;
}
return hashCode;
}
/**
* Generate a hashCode on a memory range using a more complex but slower method.
*
* @param hashCode current hashCode value
* @param addr start of the memory range to be hashed
* @param lengthInBytes length of the memory range
* @return updated hashCode value
*/
public static int getHashCodeComplex(int hashCode, int addr, int lengthInBytes) {
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, lengthInBytes, 4);
int n = lengthInBytes / 4;
for (int i = 0; i < n; i++) {
int value = memoryReader.readNext();
value = Integer.rotateLeft(value, i & 31);
hashCode ^= value + i + addr;
hashCode += i + addr;
}
return hashCode;
}
/**
* Generate a hashCode on a memory range using a more complex but slower method.
* This method also uses a stride to scan only parts of the memory range.
*
* @param hashCode current hashCode value
* @param addr start of the memory range to be hashed
* @param lengthInBytes length of the memory range
* @param strideInBytes stride (hash only 4 bytes every stride bytes)
* @return updated hashCode value
*/
public static int getHashCodeComplex(int hashCode, int addr, int lengthInBytes, int strideInBytes) {
if (strideInBytes <= 4) {
// There is no stride...
return getHashCodeComplex(hashCode, addr, lengthInBytes);
}
int skip = (strideInBytes / 4) - 1;
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, lengthInBytes, 4);
int n = lengthInBytes / strideInBytes;
for (int i = 0; i < n; i++) {
int value = memoryReader.readNext();
memoryReader.skip(skip);
value = Integer.rotateLeft(value, i & 31);
hashCode ^= value + i + addr;
hashCode += i + addr;
}
return hashCode;
}
/**
* Generate a hashCode on a memory range using a rather simple but fast method.
* The hashCode will be independent of the address, i.e. the same hashCode will
* be generated for the same data at different memory addresses.
*
* @param hashCode current hashCode value
* @param addr start of the memory range to be hashed
* @param lengthInBytes length of the memory range
* @return updated hashCode value
*/
public static int getHashCodeFloatingMemory(int hashCode, int addr, int lengthInBytes) {
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, lengthInBytes, 4);
return getHashCodeFloatingMemory(hashCode, memoryReader, lengthInBytes);
}
/**
* Generate a hashCode on a memory range using a rather simple but fast method.
* The hashCode will be independent of the address, i.e. the same hashCode will
* be generated for the same data at different memory addresses.
*
* @param hashCode current hashCode value
* @param memoryReader the memory reader for the values to be hashed
* @param lengthInBytes length of the memory range
* @return updated hashCode value
*/
public static int getHashCodeFloatingMemory(int hashCode, IMemoryReader memoryReader, int lengthInBytes) {
for (int i = 0; i < lengthInBytes; i += 4) {
int value = memoryReader.readNext();
hashCode ^= value + i;
hashCode += i;
}
return hashCode;
}
}