diff --git a/include/PerfectHash.h b/include/PerfectHash.h index a4626fa1..47a95f52 100644 --- a/include/PerfectHash.h +++ b/include/PerfectHash.h @@ -1968,6 +1968,8 @@ IsValidSeedMasks( 3, \ DECL_SEED_MASKS(0, 0, 0x1f1f, 0, 0, 0, 0, 0) \ ) \ + ENTRY(Multiply, 2, NO_SEED_MASKS) \ + ENTRY(MultiplyXor, 4, NO_SEED_MASKS) \ LAST_ENTRY(Scratch, 3, NO_SEED_MASKS) #define PERFECT_HASH_HASH_FUNCTION_TABLE_ENTRY(ENTRY) \ diff --git a/include/PerfectHashErrors.h b/include/PerfectHashErrors.h index ac25f2e3..4f50c3ee 100644 --- a/include/PerfectHashErrors.h +++ b/include/PerfectHashErrors.h @@ -252,6 +252,8 @@ Module Name: // 22 MultiplyRotateLR (3) // 23 MultiplyShiftR (3) // 24 MultiplyShiftLR (3) +// 25 Multiply (2) +// 26 MultiplyXor (4) // // N.B. The lowest latency hash functions with good solving ability, in order of // ascending latency, are: Crc32RotateX, Crc32RotateXY, Crc32RotateWXYZ. diff --git a/src/CompiledPerfectHashTable/CompiledPerfectHashTableChm01IndexMultiplyAnd.c b/src/CompiledPerfectHashTable/CompiledPerfectHashTableChm01IndexMultiplyAnd.c new file mode 100644 index 00000000..faf1f7b7 --- /dev/null +++ b/src/CompiledPerfectHashTable/CompiledPerfectHashTableChm01IndexMultiplyAnd.c @@ -0,0 +1,27 @@ + +DECLARE_INDEX_ROUTINE() +{ + CPHINDEX Index; + CPHDKEY Vertex1; + CPHDKEY Vertex2; + CPHDKEY MaskedLow; + CPHDKEY MaskedHigh; + CPHDKEY DownsizedKey; + + DownsizedKey = DOWNSIZE_KEY(Key); + + Vertex1 = DownsizedKey * SEED1; + + Vertex2 = DownsizedKey * SEED2; + + MaskedLow = Vertex1 & HASH_MASK; + MaskedHigh = Vertex2 & HASH_MASK; + + Vertex1 = TABLE_DATA[MaskedLow]; + Vertex2 = TABLE_DATA[MaskedHigh]; + + Index = (CPHINDEX)((Vertex1 + Vertex2) & INDEX_MASK); + + return Index; +} + diff --git a/src/CompiledPerfectHashTable/CompiledPerfectHashTableChm01IndexMultiplyXorAnd.c b/src/CompiledPerfectHashTable/CompiledPerfectHashTableChm01IndexMultiplyXorAnd.c new file mode 100644 index 00000000..a8731264 --- /dev/null +++ b/src/CompiledPerfectHashTable/CompiledPerfectHashTableChm01IndexMultiplyXorAnd.c @@ -0,0 +1,29 @@ + +DECLARE_INDEX_ROUTINE() +{ + CPHINDEX Index; + CPHDKEY Vertex1; + CPHDKEY Vertex2; + CPHDKEY MaskedLow; + CPHDKEY MaskedHigh; + CPHDKEY DownsizedKey; + + DownsizedKey = DOWNSIZE_KEY(Key); + + Vertex1 = DownsizedKey * SEED1; + Vertex1 ^= SEED2; + + Vertex2 = DownsizedKey * SEED3; + Vertex2 ^= SEED4; + + MaskedLow = Vertex1 & HASH_MASK; + MaskedHigh = Vertex2 & HASH_MASK; + + Vertex1 = TABLE_DATA[MaskedLow]; + Vertex2 = TABLE_DATA[MaskedHigh]; + + Index = (CPHINDEX)((Vertex1 + Vertex2) & INDEX_MASK); + + return Index; +} + diff --git a/src/PerfectHash/CompiledPerfectHashTableChm01IndexMultiplyAnd_CSource_RawCString.h b/src/PerfectHash/CompiledPerfectHashTableChm01IndexMultiplyAnd_CSource_RawCString.h new file mode 100644 index 00000000..cea2576f --- /dev/null +++ b/src/PerfectHash/CompiledPerfectHashTableChm01IndexMultiplyAnd_CSource_RawCString.h @@ -0,0 +1,57 @@ +// +// Auto-generated. +// + +DECLSPEC_ALIGN(16) +const CHAR CompiledPerfectHashTableChm01IndexMultiplyAndCSourceRawCStr[] = + "\n" + "//\n" + "// Begin CompiledPerfectHashTableChm01IndexMultiplyAnd.c.\n" + "//\n" + "\n" + "\n" + "DECLARE_INDEX_ROUTINE()\n" + "{\n" + " CPHINDEX Index;\n" + " CPHDKEY Vertex1;\n" + " CPHDKEY Vertex2;\n" + " CPHDKEY MaskedLow;\n" + " CPHDKEY MaskedHigh;\n" + " CPHDKEY DownsizedKey;\n" + "\n" + " DownsizedKey = DOWNSIZE_KEY(Key);\n" + "\n" + " Vertex1 = DownsizedKey * SEED1;\n" + "\n" + " Vertex2 = DownsizedKey * SEED2;\n" + "\n" + " MaskedLow = Vertex1 & HASH_MASK;\n" + " MaskedHigh = Vertex2 & HASH_MASK;\n" + "\n" + " Vertex1 = TABLE_DATA[MaskedLow];\n" + " Vertex2 = TABLE_DATA[MaskedHigh];\n" + "\n" + " Index = (CPHINDEX)((Vertex1 + Vertex2) & INDEX_MASK);\n" + "\n" + " return Index;\n" + "}\n" + "\n" + "\n" + "//\n" + "// End CompiledPerfectHashTableChm01IndexMultiplyAnd.c.\n" + "//\n" + "\n" +; + +const STRING CompiledPerfectHashTableChm01IndexMultiplyAndCSourceRawCString = { + sizeof(CompiledPerfectHashTableChm01IndexMultiplyAndCSourceRawCStr) - sizeof(CHAR), + sizeof(CompiledPerfectHashTableChm01IndexMultiplyAndCSourceRawCStr), +#ifdef _WIN64 + 0, +#endif + (PCHAR)&CompiledPerfectHashTableChm01IndexMultiplyAndCSourceRawCStr, +}; + +#ifndef RawCString +#define RawCString (&CompiledPerfectHashTableChm01IndexMultiplyAndCSourceRawCString) +#endif diff --git a/src/PerfectHash/CompiledPerfectHashTableChm01IndexMultiplyXorAnd_CSource_RawCString.h b/src/PerfectHash/CompiledPerfectHashTableChm01IndexMultiplyXorAnd_CSource_RawCString.h new file mode 100644 index 00000000..eb8d6a52 --- /dev/null +++ b/src/PerfectHash/CompiledPerfectHashTableChm01IndexMultiplyXorAnd_CSource_RawCString.h @@ -0,0 +1,59 @@ +// +// Auto-generated. +// + +DECLSPEC_ALIGN(16) +const CHAR CompiledPerfectHashTableChm01IndexMultiplyXorAndCSourceRawCStr[] = + "\n" + "//\n" + "// Begin CompiledPerfectHashTableChm01IndexMultiplyXorAnd.c.\n" + "//\n" + "\n" + "\n" + "DECLARE_INDEX_ROUTINE()\n" + "{\n" + " CPHINDEX Index;\n" + " CPHDKEY Vertex1;\n" + " CPHDKEY Vertex2;\n" + " CPHDKEY MaskedLow;\n" + " CPHDKEY MaskedHigh;\n" + " CPHDKEY DownsizedKey;\n" + "\n" + " DownsizedKey = DOWNSIZE_KEY(Key);\n" + "\n" + " Vertex1 = DownsizedKey * SEED1;\n" + " Vertex1 ^= SEED2;\n" + "\n" + " Vertex2 = DownsizedKey * SEED3;\n" + " Vertex2 ^= SEED4;\n" + "\n" + " MaskedLow = Vertex1 & HASH_MASK;\n" + " MaskedHigh = Vertex2 & HASH_MASK;\n" + "\n" + " Vertex1 = TABLE_DATA[MaskedLow];\n" + " Vertex2 = TABLE_DATA[MaskedHigh];\n" + "\n" + " Index = (CPHINDEX)((Vertex1 + Vertex2) & INDEX_MASK);\n" + "\n" + " return Index;\n" + "}\n" + "\n" + "\n" + "//\n" + "// End CompiledPerfectHashTableChm01IndexMultiplyXorAnd.c.\n" + "//\n" + "\n" +; + +const STRING CompiledPerfectHashTableChm01IndexMultiplyXorAndCSourceRawCString = { + sizeof(CompiledPerfectHashTableChm01IndexMultiplyXorAndCSourceRawCStr) - sizeof(CHAR), + sizeof(CompiledPerfectHashTableChm01IndexMultiplyXorAndCSourceRawCStr), +#ifdef _WIN64 + 0, +#endif + (PCHAR)&CompiledPerfectHashTableChm01IndexMultiplyXorAndCSourceRawCStr, +}; + +#ifndef RawCString +#define RawCString (&CompiledPerfectHashTableChm01IndexMultiplyXorAndCSourceRawCString) +#endif diff --git a/src/PerfectHash/CompiledPerfectHashTableIndexRoutines.h b/src/PerfectHash/CompiledPerfectHashTableIndexRoutines.h index 588a411c..441cbaaf 100644 --- a/src/PerfectHash/CompiledPerfectHashTableIndexRoutines.h +++ b/src/PerfectHash/CompiledPerfectHashTableIndexRoutines.h @@ -22,6 +22,8 @@ #include "CompiledPerfectHashTableChm01IndexMultiplyRotateLRAnd_CSource_RawCString.h" #include "CompiledPerfectHashTableChm01IndexMultiplyShiftRAnd_CSource_RawCString.h" #include "CompiledPerfectHashTableChm01IndexMultiplyShiftLRAnd_CSource_RawCString.h" +#include "CompiledPerfectHashTableChm01IndexMultiplyAnd_CSource_RawCString.h" +#include "CompiledPerfectHashTableChm01IndexMultiplyXorAnd_CSource_RawCString.h" // // Keep this last. diff --git a/src/PerfectHash/PerfectHash.vcxproj b/src/PerfectHash/PerfectHash.vcxproj index 820ef419..cd00377e 100644 --- a/src/PerfectHash/PerfectHash.vcxproj +++ b/src/PerfectHash/PerfectHash.vcxproj @@ -119,6 +119,8 @@ + + @@ -271,4 +273,4 @@ - \ No newline at end of file + diff --git a/src/PerfectHash/PerfectHash.vcxproj.filters b/src/PerfectHash/PerfectHash.vcxproj.filters index d1132917..3051c96b 100644 --- a/src/PerfectHash/PerfectHash.vcxproj.filters +++ b/src/PerfectHash/PerfectHash.vcxproj.filters @@ -489,6 +489,12 @@ Private Header Files %28Auto-Generated%29 + + Private Header Files %28Auto-Generated%29 + + + Private Header Files %28Auto-Generated%29 + Private Header Files @@ -566,4 +572,4 @@ Resource Files - \ No newline at end of file + diff --git a/src/PerfectHash/PerfectHashErrors.mc b/src/PerfectHash/PerfectHashErrors.mc index 4c9f9a4c..6238e99d 100644 --- a/src/PerfectHash/PerfectHashErrors.mc +++ b/src/PerfectHash/PerfectHashErrors.mc @@ -198,6 +198,8 @@ Hash Functions: 22 MultiplyRotateLR (3) 23 MultiplyShiftR (3) 24 MultiplyShiftLR (3) + 25 Multiply (2) + 26 MultiplyXor (4) N.B. The lowest latency hash functions with good solving ability, in order of ascending latency, are: Crc32RotateX, Crc32RotateXY, Crc32RotateWXYZ. diff --git a/src/PerfectHash/PerfectHashErrors_English.bin b/src/PerfectHash/PerfectHashErrors_English.bin index 77c017f8..8274a1b6 100644 Binary files a/src/PerfectHash/PerfectHashErrors_English.bin and b/src/PerfectHash/PerfectHashErrors_English.bin differ diff --git a/src/PerfectHash/PerfectHashTableHash.c b/src/PerfectHash/PerfectHashTableHash.c index 3839d6f9..797b3595 100644 --- a/src/PerfectHash/PerfectHashTableHash.c +++ b/src/PerfectHash/PerfectHashTableHash.c @@ -2670,5 +2670,195 @@ PerfectHashTableHashMultiplyShiftLR( ); } +_Use_decl_annotations_ +HRESULT +PerfectHashTableSeededHashMultiply( + PPERFECT_HASH_TABLE Table, + ULONG Key, + ULONG NumberOfSeeds, + PULONG Seeds, + PULONGLONG Hash + ) +/*++ + +Routine Description: + + Performs a single multiply on each vertex. + +Arguments: + + Table - Supplies a pointer to the table for which the hash is being created. + + Key - Supplies the input value to hash. + + NumberOfSeeds - Supplies the number of elements in the Seeds array. + + Seeds - Supplies an array of ULONG seed values. + + Hash - Receives two 32-bit hashes merged into a 64-bit value. + +Return Value: + + S_OK on success. If the two 32-bit hash values are identical, E_FAIL. + +--*/ +{ + ULONG Seed1; + ULONG Seed2; + ULONG Vertex1; + ULONG Vertex2; + ULONG DownsizedKey; + ULARGE_INTEGER Result; + + UNREFERENCED_PARAMETER(Table); + + ASSERT(NumberOfSeeds >= 2); + UNREFERENCED_PARAMETER(NumberOfSeeds); + + // + // Initialize aliases. + // + + Seed1 = Seeds[0]; + Seed2 = Seeds[1]; + DownsizedKey = Key; + + // + // Calculate the individual hash parts. + // + + Vertex1 = DownsizedKey * Seed1; + + Vertex2 = DownsizedKey * Seed2; + + if (Vertex1 == Vertex2) { + return E_FAIL; + } + + Result.LowPart = Vertex1; + Result.HighPart = Vertex2; + + *Hash = Result.QuadPart; + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT +PerfectHashTableHashMultiply( + PPERFECT_HASH_TABLE Table, + ULONG Key, + PULONGLONG Hash + ) +{ + PTABLE_INFO_ON_DISK TableInfo = Table->TableInfoOnDisk; + + return PerfectHashTableSeededHashMultiply( + Table, + Key, + TableInfo->NumberOfSeeds, + &TableInfo->FirstSeed, + Hash + ); +} + +_Use_decl_annotations_ +HRESULT +PerfectHashTableSeededHashMultiplyXor( + PPERFECT_HASH_TABLE Table, + ULONG Key, + ULONG NumberOfSeeds, + PULONG Seeds, + PULONGLONG Hash + ) +/*++ + +Routine Description: + + Performs a multiply then xor on each vertex. + +Arguments: + + Table - Supplies a pointer to the table for which the hash is being created. + + Key - Supplies the input value to hash. + + NumberOfSeeds - Supplies the number of elements in the Seeds array. + + Seeds - Supplies an array of ULONG seed values. + + Hash - Receives two 32-bit hashes merged into a 64-bit value. + +Return Value: + + S_OK on success. If the two 32-bit hash values are identical, E_FAIL. + +--*/ +{ + ULONG Seed1; + ULONG Seed2; + ULONG Seed3; + ULONG Seed4; + ULONG Vertex1; + ULONG Vertex2; + ULONG DownsizedKey; + ULARGE_INTEGER Result; + + UNREFERENCED_PARAMETER(Table); + + ASSERT(NumberOfSeeds >= 4); + UNREFERENCED_PARAMETER(NumberOfSeeds); + + // + // Initialize aliases. + // + + Seed1 = Seeds[0]; + Seed2 = Seeds[1]; + Seed3 = Seeds[2]; + Seed4 = Seeds[3]; + DownsizedKey = Key; + + // + // Calculate the individual hash parts. + // + + Vertex1 = DownsizedKey * Seed1; + Vertex1 ^= Seed2; + + Vertex2 = DownsizedKey * Seed3; + Vertex2 ^= Seed4; + + if (Vertex1 == Vertex2) { + return E_FAIL; + } + + Result.LowPart = Vertex1; + Result.HighPart = Vertex2; + + *Hash = Result.QuadPart; + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT +PerfectHashTableHashMultiplyXor( + PPERFECT_HASH_TABLE Table, + ULONG Key, + PULONGLONG Hash + ) +{ + PTABLE_INFO_ON_DISK TableInfo = Table->TableInfoOnDisk; + + return PerfectHashTableSeededHashMultiplyXor( + Table, + Key, + TableInfo->NumberOfSeeds, + &TableInfo->FirstSeed, + Hash + ); +} + // vim:set ts=8 sw=4 sts=4 tw=80 expandtab :