From: khizmax Date: Sat, 5 Sep 2015 17:24:21 +0000 (+0300) Subject: Added MD5, SHA256, CityHash hash function for MultiLevelHashMap testing X-Git-Tag: v2.1.0~133 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b2ad653c18478b7d423a34a4794fafde840aef97;p=libcds.git Added MD5, SHA256, CityHash hash function for MultiLevelHashMap testing --- diff --git a/doxygen/image/multilevel_hashset.png b/doxygen/image/multilevel_hashset.png index 2df82c0b..63b213bc 100644 Binary files a/doxygen/image/multilevel_hashset.png and b/doxygen/image/multilevel_hashset.png differ diff --git a/projects/Win/vc12/unit-prerequisites.vcxproj b/projects/Win/vc12/unit-prerequisites.vcxproj index 4d40f1a8..848ab3a8 100644 --- a/projects/Win/vc12/unit-prerequisites.vcxproj +++ b/projects/Win/vc12/unit-prerequisites.vcxproj @@ -415,12 +415,19 @@ + + + + + + + diff --git a/projects/source.test-common.mk b/projects/source.test-common.mk index a867a529..99b66930 100644 --- a/projects/source.test-common.mk +++ b/projects/source.test-common.mk @@ -3,4 +3,9 @@ CDS_TESTCOMMON_SOURCES := \ tests/cppunit/test_main.cpp \ tests/cppunit/thread.cpp \ tests/unit/michael_alloc.cpp \ - tests/unit/ellen_bintree_update_desc_pool.cpp + tests/unit/ellen_bintree_update_desc_pool.cpp \ + tests/hashing/city.cc \ + tests/hashing/md5.cpp \ + tests/hashing/sha256.cpp + + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index af28e734..3c77e1af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,7 +5,10 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set(SOURCES cppunit/test_main.cpp cppunit/thread.cpp unit/michael_alloc.cpp - unit/ellen_bintree_update_desc_pool.cpp) + unit/ellen_bintree_update_desc_pool.cpp + hashing/city.cc + hashing/md5.cpp + hashing/sha256.cpp) add_library(${TEST_COMMON} OBJECT ${SOURCES}) diff --git a/tests/hashing/city.cc b/tests/hashing/city.cc new file mode 100644 index 00000000..c33aec06 --- /dev/null +++ b/tests/hashing/city.cc @@ -0,0 +1,628 @@ +// Copyright (c) 2011 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// CityHash, by Geoff Pike and Jyrki Alakuijala +// +// This file provides CityHash64() and related functions. +// +// It's probably possible to create even faster hash functions by +// writing a program that systematically explores some of the space of +// possible hash functions, by using SIMD instructions, or by +// compromising on hash quality. + +//#include "config.h" +#include "city.h" + +#include +#include // for memcpy and memset + +using namespace std; + +static uint64 UNALIGNED_LOAD64(const char *p) { + uint64 result; + memcpy(&result, p, sizeof(result)); + return result; +} + +static uint32 UNALIGNED_LOAD32(const char *p) { + uint32 result; + memcpy(&result, p, sizeof(result)); + return result; +} + +#ifdef _MSC_VER + +#include +#define bswap_32(x) _byteswap_ulong(x) +#define bswap_64(x) _byteswap_uint64(x) + +#elif defined(__APPLE__) + +// Mac OS X / Darwin features +#include +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) + +#elif defined(__NetBSD__) + +#include +#include +#if defined(__BSWAP_RENAME) && !defined(__bswap_32) +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) +#endif + +#else + +#include + +#endif + +#ifdef WORDS_BIGENDIAN +#define uint32_in_expected_order(x) (bswap_32(x)) +#define uint64_in_expected_order(x) (bswap_64(x)) +#else +#define uint32_in_expected_order(x) (x) +#define uint64_in_expected_order(x) (x) +#endif + +#if !defined(LIKELY) +#if HAVE_BUILTIN_EXPECT +#define LIKELY(x) (__builtin_expect(!!(x), 1)) +#else +#define LIKELY(x) (x) +#endif +#endif + +static uint64 Fetch64(const char *p) { + return uint64_in_expected_order(UNALIGNED_LOAD64(p)); +} + +static uint32 Fetch32(const char *p) { + return uint32_in_expected_order(UNALIGNED_LOAD32(p)); +} + +// Some primes between 2^63 and 2^64 for various uses. +static const uint64 k0 = 0xc3a5c85c97cb3127ULL; +static const uint64 k1 = 0xb492b66fbe98f273ULL; +static const uint64 k2 = 0x9ae16a3b2f90404fULL; + +// Magic numbers for 32-bit hashing. Copied from Murmur3. +static const uint32_t c1 = 0xcc9e2d51; +static const uint32_t c2 = 0x1b873593; + +// A 32-bit to 32-bit integer hash copied from Murmur3. +static uint32 fmix(uint32 h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} + +static uint32 Rotate32(uint32 val, int shift) { + // Avoid shifting by 32: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (32 - shift))); +} + +#undef PERMUTE3 +#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0) + +static uint32 Mur(uint32 a, uint32 h) { + // Helper from Murmur3 for combining two 32-bit values. + a *= c1; + a = Rotate32(a, 17); + a *= c2; + h ^= a; + h = Rotate32(h, 19); + return h * 5 + 0xe6546b64; +} + +static uint32 Hash32Len13to24(const char *s, size_t len) { + uint32 a = Fetch32(s - 4 + (len >> 1)); + uint32 b = Fetch32(s + 4); + uint32 c = Fetch32(s + len - 8); + uint32 d = Fetch32(s + (len >> 1)); + uint32 e = Fetch32(s); + uint32 f = Fetch32(s + len - 4); + uint32 h = len; + + return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); +} + +static uint32 Hash32Len0to4(const char *s, size_t len) { + uint32 b = 0; + uint32 c = 9; + for (int i = 0; i < len; i++) { + signed char v = s[i]; + b = b * c1 + v; + c ^= b; + } + return fmix(Mur(b, Mur(len, c))); +} + +static uint32 Hash32Len5to12(const char *s, size_t len) { + uint32 a = len, b = len * 5, c = 9, d = b; + a += Fetch32(s); + b += Fetch32(s + len - 4); + c += Fetch32(s + ((len >> 1) & 4)); + return fmix(Mur(c, Mur(b, Mur(a, d)))); +} + +uint32 CityHash32(const char *s, size_t len) { + if (len <= 24) { + return len <= 12 ? + (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) : + Hash32Len13to24(s, len); + } + + // len > 24 + uint32 h = len, g = c1 * len, f = g; + uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2; + uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2; + uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2; + uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2; + uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2; + h ^= a0; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + h ^= a2; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a1; + g = Rotate32(g, 19); + g = g * 5 + 0xe6546b64; + g ^= a3; + g = Rotate32(g, 19); + g = g * 5 + 0xe6546b64; + f += a4; + f = Rotate32(f, 19); + f = f * 5 + 0xe6546b64; + size_t iters = (len - 1) / 20; + do { + uint32 a0 = Rotate32(Fetch32(s) * c1, 17) * c2; + uint32 a1 = Fetch32(s + 4); + uint32 a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2; + uint32 a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2; + uint32 a4 = Fetch32(s + 16); + h ^= a0; + h = Rotate32(h, 18); + h = h * 5 + 0xe6546b64; + f += a1; + f = Rotate32(f, 19); + f = f * c1; + g += a2; + g = Rotate32(g, 18); + g = g * 5 + 0xe6546b64; + h ^= a3 + a1; + h = Rotate32(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a4; + g = bswap_32(g) * 5; + h += a4 * 5; + h = bswap_32(h); + f += a0; + PERMUTE3(f, h, g); + s += 20; + } while (--iters != 0); + g = Rotate32(g, 11) * c1; + g = Rotate32(g, 17) * c1; + f = Rotate32(f, 11) * c1; + f = Rotate32(f, 17) * c1; + h = Rotate32(h + g, 19); + h = h * 5 + 0xe6546b64; + h = Rotate32(h, 17) * c1; + h = Rotate32(h + f, 19); + h = h * 5 + 0xe6546b64; + h = Rotate32(h, 17) * c1; + return h; +} + +// Bitwise right rotate. Normally this will compile to a single +// instruction, especially if the shift is a manifest constant. +static uint64 Rotate(uint64 val, int shift) { + // Avoid shifting by 64: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); +} + +static uint64 ShiftMix(uint64 val) { + return val ^ (val >> 47); +} + +static uint64 HashLen16(uint64 u, uint64 v) { + return Hash128to64(uint128(u, v)); +} + +static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) { + // Murmur-inspired hashing. + uint64 a = (u ^ v) * mul; + a ^= (a >> 47); + uint64 b = (v ^ a) * mul; + b ^= (b >> 47); + b *= mul; + return b; +} + +static uint64 HashLen0to16(const char *s, size_t len) { + if (len >= 8) { + uint64 mul = k2 + len * 2; + uint64 a = Fetch64(s) + k2; + uint64 b = Fetch64(s + len - 8); + uint64 c = Rotate(b, 37) * mul + a; + uint64 d = (Rotate(a, 25) + b) * mul; + return HashLen16(c, d, mul); + } + if (len >= 4) { + uint64 mul = k2 + len * 2; + uint64 a = Fetch32(s); + return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); + } + if (len > 0) { + uint8 a = s[0]; + uint8 b = s[len >> 1]; + uint8 c = s[len - 1]; + uint32 y = static_cast(a) + (static_cast(b) << 8); + uint32 z = len + (static_cast(c) << 2); + return ShiftMix(y * k2 ^ z * k0) * k2; + } + return k2; +} + +// This probably works well for 16-byte strings as well, but it may be overkill +// in that case. +static uint64 HashLen17to32(const char *s, size_t len) { + uint64 mul = k2 + len * 2; + uint64 a = Fetch64(s) * k1; + uint64 b = Fetch64(s + 8); + uint64 c = Fetch64(s + len - 8) * mul; + uint64 d = Fetch64(s + len - 16) * k2; + return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, + a + Rotate(b + k2, 18) + c, mul); +} + +// Return a 16-byte hash for 48 bytes. Quick and dirty. +// Callers do best to use "random-looking" values for a and b. +static pair WeakHashLen32WithSeeds( + uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) { + a += w; + b = Rotate(b + a + z, 21); + uint64 c = a; + a += x; + a += y; + b += Rotate(a, 44); + return make_pair(a + z, b + c); +} + +// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. +static pair WeakHashLen32WithSeeds( + const char* s, uint64 a, uint64 b) { + return WeakHashLen32WithSeeds(Fetch64(s), + Fetch64(s + 8), + Fetch64(s + 16), + Fetch64(s + 24), + a, + b); +} + +// Return an 8-byte hash for 33 to 64 bytes. +static uint64 HashLen33to64(const char *s, size_t len) { + uint64 mul = k2 + len * 2; + uint64 a = Fetch64(s) * k2; + uint64 b = Fetch64(s + 8); + uint64 c = Fetch64(s + len - 24); + uint64 d = Fetch64(s + len - 32); + uint64 e = Fetch64(s + 16) * k2; + uint64 f = Fetch64(s + 24) * 9; + uint64 g = Fetch64(s + len - 8); + uint64 h = Fetch64(s + len - 16) * mul; + uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9; + uint64 v = ((a + g) ^ d) + f + 1; + uint64 w = bswap_64((u + v) * mul) + h; + uint64 x = Rotate(e + f, 42) + c; + uint64 y = (bswap_64((v + w) * mul) + g) * mul; + uint64 z = e + f + c; + a = bswap_64((x + z) * mul + y) + b; + b = ShiftMix((z + a) * mul + d + h) * mul; + return b + x; +} + +uint64 CityHash64(const char *s, size_t len) { + if (len <= 32) { + if (len <= 16) { + return HashLen0to16(s, len); + } else { + return HashLen17to32(s, len); + } + } else if (len <= 64) { + return HashLen33to64(s, len); + } + + // For strings over 64 bytes we hash the end first, and then as we + // loop we keep 56 bytes of state: v, w, x, y, and z. + uint64 x = Fetch64(s + len - 40); + uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56); + uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); + pair v = WeakHashLen32WithSeeds(s + len - 64, len, z); + pair w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); + x = x * k1 + Fetch64(s); + + // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. + len = (len - 1) & ~static_cast(63); + do { + x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch64(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + std::swap(z, x); + s += 64; + len -= 64; + } while (len != 0); + return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z, + HashLen16(v.second, w.second) + x); +} + +uint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) { + return CityHash64WithSeeds(s, len, k2, seed); +} + +uint64 CityHash64WithSeeds(const char *s, size_t len, + uint64 seed0, uint64 seed1) { + return HashLen16(CityHash64(s, len) - seed0, seed1); +} + +// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings +// of any length representable in signed long. Based on City and Murmur. +static uint128 CityMurmur(const char *s, size_t len, uint128 seed) { + uint64 a = Uint128Low64(seed); + uint64 b = Uint128High64(seed); + uint64 c = 0; + uint64 d = 0; + signed long l = len - 16; + if (l <= 0) { // len <= 16 + a = ShiftMix(a * k1) * k1; + c = b * k1 + HashLen0to16(s, len); + d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c)); + } else { // len > 16 + c = HashLen16(Fetch64(s + len - 8) + k1, a); + d = HashLen16(b + len, c + Fetch64(s + len - 16)); + a += d; + do { + a ^= ShiftMix(Fetch64(s) * k1) * k1; + a *= k1; + b ^= a; + c ^= ShiftMix(Fetch64(s + 8) * k1) * k1; + c *= k1; + d ^= c; + s += 16; + l -= 16; + } while (l > 0); + } + a = HashLen16(a, c); + b = HashLen16(d, b); + return uint128(a ^ b, HashLen16(b, a)); +} + +uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { + if (len < 128) { + return CityMurmur(s, len, seed); + } + + // We expect len >= 128 to be the common case. Keep 56 bytes of state: + // v, w, x, y, and z. + pair v, w; + uint64 x = Uint128Low64(seed); + uint64 y = Uint128High64(seed); + uint64 z = len * k1; + v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s); + v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8); + w.first = Rotate(y + z, 35) * k1 + x; + w.second = Rotate(x + Fetch64(s + 88), 53) * k1; + + // This is the same inner loop as CityHash64(), manually unrolled. + do { + x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch64(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + std::swap(z, x); + s += 64; + x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch64(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); + std::swap(z, x); + s += 64; + len -= 128; + } while (LIKELY(len >= 128)); + x += Rotate(v.first + z, 49) * k0; + y = y * k0 + Rotate(w.second, 37); + z = z * k0 + Rotate(w.first, 27); + w.first *= 9; + v.first *= k0; + // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. + for (size_t tail_done = 0; tail_done < len; ) { + tail_done += 32; + y = Rotate(x + y, 42) * k0 + v.second; + w.first += Fetch64(s + len - tail_done + 16); + x = x * k0 + w.first; + z += w.second + Fetch64(s + len - tail_done); + w.second += v.first; + v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second); + v.first *= k0; + } + // At this point our 56 bytes of state should contain more than + // enough information for a strong 128-bit hash. We use two + // different 56-byte-to-8-byte hashes to get a 16-byte final result. + x = HashLen16(x, v.first); + y = HashLen16(y + z, w.first); + return uint128(HashLen16(x + v.second, w.second) + y, + HashLen16(x + w.second, y + v.second)); +} + +uint128 CityHash128(const char *s, size_t len) { + return len >= 16 ? + CityHash128WithSeed(s + 16, len - 16, + uint128(Fetch64(s), Fetch64(s + 8) + k0)) : + CityHash128WithSeed(s, len, uint128(k0, k1)); +} + +#ifdef __SSE4_2__ +#include +#include + +// Requires len >= 240. +static void CityHashCrc256Long(const char *s, size_t len, + uint32 seed, uint64 *result) { + uint64 a = Fetch64(s + 56) + k0; + uint64 b = Fetch64(s + 96) + k0; + uint64 c = result[0] = HashLen16(b, len); + uint64 d = result[1] = Fetch64(s + 120) * k0 + len; + uint64 e = Fetch64(s + 184) + seed; + uint64 f = 0; + uint64 g = 0; + uint64 h = c + d; + uint64 x = seed; + uint64 y = 0; + uint64 z = 0; + + // 240 bytes of input per iter. + size_t iters = len / 240; + len -= iters * 240; + do { +#undef CHUNK +#define CHUNK(r) \ + PERMUTE3(x, z, y); \ + b += Fetch64(s); \ + c += Fetch64(s + 8); \ + d += Fetch64(s + 16); \ + e += Fetch64(s + 24); \ + f += Fetch64(s + 32); \ + a += b; \ + h += f; \ + b += c; \ + f += d; \ + g += e; \ + e += z; \ + g += x; \ + z = _mm_crc32_u64(z, b + g); \ + y = _mm_crc32_u64(y, e + h); \ + x = _mm_crc32_u64(x, f + a); \ + e = Rotate(e, r); \ + c += e; \ + s += 40 + + CHUNK(0); PERMUTE3(a, h, c); + CHUNK(33); PERMUTE3(a, h, f); + CHUNK(0); PERMUTE3(b, h, f); + CHUNK(42); PERMUTE3(b, h, d); + CHUNK(0); PERMUTE3(b, h, e); + CHUNK(33); PERMUTE3(a, h, e); + } while (--iters > 0); + + while (len >= 40) { + CHUNK(29); + e ^= Rotate(a, 20); + h += Rotate(b, 30); + g ^= Rotate(c, 40); + f += Rotate(d, 34); + PERMUTE3(c, h, g); + len -= 40; + } + if (len > 0) { + s = s + len - 40; + CHUNK(33); + e ^= Rotate(a, 43); + h += Rotate(b, 42); + g ^= Rotate(c, 41); + f += Rotate(d, 40); + } + result[0] ^= h; + result[1] ^= g; + g += h; + a = HashLen16(a, g + z); + x += y << 32; + b += x; + c = HashLen16(c, z) + h; + d = HashLen16(d, e + result[0]); + g += e; + h += HashLen16(x, f); + e = HashLen16(a, d) + g; + z = HashLen16(b, c) + a; + y = HashLen16(g, h) + c; + result[0] = e + z + y + x; + a = ShiftMix((a + y) * k0) * k0 + b; + result[1] += a + result[0]; + a = ShiftMix(a * k0) * k0 + c; + result[2] = a + result[1]; + a = ShiftMix((a + e) * k0) * k0; + result[3] = a + result[2]; +} + +// Requires len < 240. +static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) { + char buf[240]; + memcpy(buf, s, len); + memset(buf + len, 0, 240 - len); + CityHashCrc256Long(buf, 240, ~static_cast(len), result); +} + +void CityHashCrc256(const char *s, size_t len, uint64 *result) { + if (LIKELY(len >= 240)) { + CityHashCrc256Long(s, len, 0, result); + } else { + CityHashCrc256Short(s, len, result); + } +} + +uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) { + if (len <= 900) { + return CityHash128WithSeed(s, len, seed); + } else { + uint64 result[4]; + CityHashCrc256(s, len, result); + uint64 u = Uint128High64(seed) + result[0]; + uint64 v = Uint128Low64(seed) + result[1]; + return uint128(HashLen16(u, v + result[2]), + HashLen16(Rotate(v, 32), u * k0 + result[3])); + } +} + +uint128 CityHashCrc128(const char *s, size_t len) { + if (len <= 900) { + return CityHash128(s, len); + } else { + uint64 result[4]; + CityHashCrc256(s, len, result); + return uint128(result[2], result[3]); + } +} + +#endif diff --git a/tests/hashing/city.h b/tests/hashing/city.h new file mode 100644 index 00000000..94499ce4 --- /dev/null +++ b/tests/hashing/city.h @@ -0,0 +1,112 @@ +// Copyright (c) 2011 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// CityHash, by Geoff Pike and Jyrki Alakuijala +// +// http://code.google.com/p/cityhash/ +// +// This file provides a few functions for hashing strings. All of them are +// high-quality functions in the sense that they pass standard tests such +// as Austin Appleby's SMHasher. They are also fast. +// +// For 64-bit x86 code, on short strings, we don't know of anything faster than +// CityHash64 that is of comparable quality. We believe our nearest competitor +// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash +// tables and most other hashing (excluding cryptography). +// +// For 64-bit x86 code, on long strings, the picture is more complicated. +// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc., +// CityHashCrc128 appears to be faster than all competitors of comparable +// quality. CityHash128 is also good but not quite as fast. We believe our +// nearest competitor is Bob Jenkins' Spooky. We don't have great data for +// other 64-bit CPUs, but for long strings we know that Spooky is slightly +// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example. +// Note that CityHashCrc128 is declared in citycrc.h. +// +// For 32-bit x86 code, we don't know of anything faster than CityHash32 that +// is of comparable quality. We believe our nearest competitor is Murmur3A. +// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.) +// +// Functions in the CityHash family are not suitable for cryptography. +// +// Please see CityHash's README file for more details on our performance +// measurements and so on. +// +// WARNING: This code has been only lightly tested on big-endian platforms! +// It is known to work well on little-endian platforms that have a small penalty +// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. +// It should work on all 32-bit and 64-bit platforms that allow unaligned reads; +// bug reports are welcome. +// +// By the way, for some hash functions, given strings a and b, the hash +// of a+b is easily derived from the hashes of a and b. This property +// doesn't hold for any hash functions in this file. + +#ifndef CITY_HASH_H_ +#define CITY_HASH_H_ + +#include // for size_t. +#include +#include + +typedef uint8_t uint8; +typedef uint32_t uint32; +typedef uint64_t uint64; +typedef std::pair uint128; + +inline uint64 Uint128Low64(const uint128& x) { return x.first; } +inline uint64 Uint128High64(const uint128& x) { return x.second; } + +// Hash function for a byte array. +uint64 CityHash64(const char *buf, size_t len); + +// Hash function for a byte array. For convenience, a 64-bit seed is also +// hashed into the result. +uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed); + +// Hash function for a byte array. For convenience, two seeds are also +// hashed into the result. +uint64 CityHash64WithSeeds(const char *buf, size_t len, + uint64 seed0, uint64 seed1); + +// Hash function for a byte array. +uint128 CityHash128(const char *s, size_t len); + +// Hash function for a byte array. For convenience, a 128-bit seed is also +// hashed into the result. +uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed); + +// Hash function for a byte array. Most useful in 32-bit binaries. +uint32 CityHash32(const char *buf, size_t len); + +// Hash 128 input bits down to 64 bits of output. +// This is intended to be a reasonably good hash function. +inline uint64 Hash128to64(const uint128& x) { + // Murmur-inspired hashing. + const uint64 kMul = 0x9ddfea08eb382d69ULL; + uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; + a ^= (a >> 47); + uint64 b = (Uint128High64(x) ^ a) * kMul; + b ^= (b >> 47); + b *= kMul; + return b; +} + +#endif // CITY_HASH_H_ diff --git a/tests/hashing/hash_func.h b/tests/hashing/hash_func.h new file mode 100644 index 00000000..3ea5ce92 --- /dev/null +++ b/tests/hashing/hash_func.h @@ -0,0 +1,110 @@ +//$$CDS-header$$ + +#ifndef CDSUNIT_HASH_FUNC_H +#define CDSUNIT_HASH_FUNC_H + +#include "hashing/sha256.h" +#include "hashing/md5.h" +#include "hashing/city.h" + +namespace hashing { + + template + class hasher { + typedef Hasher hasher_type; + hasher_type m_hasher; + public: + struct hash_type { + uint8_t h[hasher_type::HashBytes]; + }; + + hash_type operator()( void const * pBuf, size_t len ) + { + m_hasher.reset(); + m_hasher.add(pBuf, len); + hash_type result; + m_hasher.getHash( result.h ); + return result; + } + + hash_type operator()( std::string const& s ) + { + return operator()( reinterpret_cast(s.c_str()), s.length()); + } + + template + hash_type operator()( T const& s ) + { + return operator()( reinterpret_cast(&s), sizeof(s)); + } + }; + + typedef hasher sha256; + typedef hasher md5; + + class city32 { + public: + typedef uint32_t hash_type; + + hash_type operator()( void const * pBuf, size_t len ) + { + return CityHash32( reinterpret_cast( pBuf ), len ); + } + + hash_type operator()( std::string const& s ) + { + return CityHash32( s.c_str(), s.length() ); + } + + template + hash_type operator()( T const& s ) + { + return CityHash32( reinterpret_cast( &s ), sizeof(s)); + } + }; + + class city64 { + public: + typedef uint64_t hash_type; + + hash_type operator()( void const * pBuf, size_t len ) + { + return CityHash64( reinterpret_cast( pBuf ), len ); + } + + hash_type operator()( std::string const& s ) + { + return CityHash64( s.c_str(), s.length() ); + } + + template + hash_type operator()( T const& s ) + { + return CityHash64( reinterpret_cast( &s ), sizeof(s)); + } + }; + + class city128 { + public: + typedef uint128 hash_type; + + hash_type operator()( void const * pBuf, size_t len ) + { + return CityHash128( reinterpret_cast( pBuf ), len ); + } + + hash_type operator()( std::string const& s ) + { + return CityHash128( s.c_str(), s.length() ); + } + + template + hash_type operator()( T const& s ) + { + return CityHash128( reinterpret_cast( &s ), sizeof(s)); + } + }; + +} // namespace hashing + +#endif // #ifndef CDSUNIT_HASH_FUNC_H diff --git a/tests/hashing/md5.cpp b/tests/hashing/md5.cpp new file mode 100644 index 00000000..27433195 --- /dev/null +++ b/tests/hashing/md5.cpp @@ -0,0 +1,380 @@ +// ////////////////////////////////////////////////////////// +// md5.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "md5.h" + +#ifndef _MSC_VER +#include +#endif + + +/// same as reset() +MD5::MD5() +{ + reset(); +} + + +/// restart +void MD5::reset() +{ + m_numBytes = 0; + m_bufferSize = 0; + + // according to RFC 1321 + m_hash[0] = 0x67452301; + m_hash[1] = 0xefcdab89; + m_hash[2] = 0x98badcfe; + m_hash[3] = 0x10325476; +} + + +namespace +{ + // mix functions for processBlock() + inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d) + { + return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d); + } + + inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d) + { + return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d)); + } + + inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d) + { + return b ^ c ^ d; + } + + inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d) + { + return c ^ (b | ~d); + } + + inline uint32_t rotate(uint32_t a, uint32_t c) + { + return (a << c) | (a >> (32 - c)); + } + +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) + inline uint32_t swap(uint32_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + } +#endif +} + + +/// process 64 bytes +void MD5::processBlock(const void* data) +{ + // get last hash + uint32_t a = m_hash[0]; + uint32_t b = m_hash[1]; + uint32_t c = m_hash[2]; + uint32_t d = m_hash[3]; + + // data represented as 16x 32-bit words + const uint32_t* words = (uint32_t*) data; + + // computations are little endian, swap data if necessary +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) +#define LITTLEENDIAN(x) swap(x) +#else +#define LITTLEENDIAN(x) (x) +#endif + + // first round + uint32_t word0 = LITTLEENDIAN(words[ 0]); + a = rotate(a + f1(b,c,d) + word0 + 0xd76aa478, 7) + b; + uint32_t word1 = LITTLEENDIAN(words[ 1]); + d = rotate(d + f1(a,b,c) + word1 + 0xe8c7b756, 12) + a; + uint32_t word2 = LITTLEENDIAN(words[ 2]); + c = rotate(c + f1(d,a,b) + word2 + 0x242070db, 17) + d; + uint32_t word3 = LITTLEENDIAN(words[ 3]); + b = rotate(b + f1(c,d,a) + word3 + 0xc1bdceee, 22) + c; + + uint32_t word4 = LITTLEENDIAN(words[ 4]); + a = rotate(a + f1(b,c,d) + word4 + 0xf57c0faf, 7) + b; + uint32_t word5 = LITTLEENDIAN(words[ 5]); + d = rotate(d + f1(a,b,c) + word5 + 0x4787c62a, 12) + a; + uint32_t word6 = LITTLEENDIAN(words[ 6]); + c = rotate(c + f1(d,a,b) + word6 + 0xa8304613, 17) + d; + uint32_t word7 = LITTLEENDIAN(words[ 7]); + b = rotate(b + f1(c,d,a) + word7 + 0xfd469501, 22) + c; + + uint32_t word8 = LITTLEENDIAN(words[ 8]); + a = rotate(a + f1(b,c,d) + word8 + 0x698098d8, 7) + b; + uint32_t word9 = LITTLEENDIAN(words[ 9]); + d = rotate(d + f1(a,b,c) + word9 + 0x8b44f7af, 12) + a; + uint32_t word10 = LITTLEENDIAN(words[10]); + c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d; + uint32_t word11 = LITTLEENDIAN(words[11]); + b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c; + + uint32_t word12 = LITTLEENDIAN(words[12]); + a = rotate(a + f1(b,c,d) + word12 + 0x6b901122, 7) + b; + uint32_t word13 = LITTLEENDIAN(words[13]); + d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a; + uint32_t word14 = LITTLEENDIAN(words[14]); + c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d; + uint32_t word15 = LITTLEENDIAN(words[15]); + b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c; + + // second round + a = rotate(a + f2(b,c,d) + word1 + 0xf61e2562, 5) + b; + d = rotate(d + f2(a,b,c) + word6 + 0xc040b340, 9) + a; + c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d; + b = rotate(b + f2(c,d,a) + word0 + 0xe9b6c7aa, 20) + c; + + a = rotate(a + f2(b,c,d) + word5 + 0xd62f105d, 5) + b; + d = rotate(d + f2(a,b,c) + word10 + 0x02441453, 9) + a; + c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d; + b = rotate(b + f2(c,d,a) + word4 + 0xe7d3fbc8, 20) + c; + + a = rotate(a + f2(b,c,d) + word9 + 0x21e1cde6, 5) + b; + d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6, 9) + a; + c = rotate(c + f2(d,a,b) + word3 + 0xf4d50d87, 14) + d; + b = rotate(b + f2(c,d,a) + word8 + 0x455a14ed, 20) + c; + + a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905, 5) + b; + d = rotate(d + f2(a,b,c) + word2 + 0xfcefa3f8, 9) + a; + c = rotate(c + f2(d,a,b) + word7 + 0x676f02d9, 14) + d; + b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c; + + // third round + a = rotate(a + f3(b,c,d) + word5 + 0xfffa3942, 4) + b; + d = rotate(d + f3(a,b,c) + word8 + 0x8771f681, 11) + a; + c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d; + b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c; + + a = rotate(a + f3(b,c,d) + word1 + 0xa4beea44, 4) + b; + d = rotate(d + f3(a,b,c) + word4 + 0x4bdecfa9, 11) + a; + c = rotate(c + f3(d,a,b) + word7 + 0xf6bb4b60, 16) + d; + b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c; + + a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6, 4) + b; + d = rotate(d + f3(a,b,c) + word0 + 0xeaa127fa, 11) + a; + c = rotate(c + f3(d,a,b) + word3 + 0xd4ef3085, 16) + d; + b = rotate(b + f3(c,d,a) + word6 + 0x04881d05, 23) + c; + + a = rotate(a + f3(b,c,d) + word9 + 0xd9d4d039, 4) + b; + d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a; + c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d; + b = rotate(b + f3(c,d,a) + word2 + 0xc4ac5665, 23) + c; + + // fourth round + a = rotate(a + f4(b,c,d) + word0 + 0xf4292244, 6) + b; + d = rotate(d + f4(a,b,c) + word7 + 0x432aff97, 10) + a; + c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d; + b = rotate(b + f4(c,d,a) + word5 + 0xfc93a039, 21) + c; + + a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3, 6) + b; + d = rotate(d + f4(a,b,c) + word3 + 0x8f0ccc92, 10) + a; + c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d; + b = rotate(b + f4(c,d,a) + word1 + 0x85845dd1, 21) + c; + + a = rotate(a + f4(b,c,d) + word8 + 0x6fa87e4f, 6) + b; + d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a; + c = rotate(c + f4(d,a,b) + word6 + 0xa3014314, 15) + d; + b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c; + + a = rotate(a + f4(b,c,d) + word4 + 0xf7537e82, 6) + b; + d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a; + c = rotate(c + f4(d,a,b) + word2 + 0x2ad7d2bb, 15) + d; + b = rotate(b + f4(c,d,a) + word9 + 0xeb86d391, 21) + c; + + // update hash + m_hash[0] += a; + m_hash[1] += b; + m_hash[2] += c; + m_hash[3] += d; +} + + +/// add arbitrary number of bytes +void MD5::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < BlockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == BlockSize) + { + processBlock(m_buffer); + m_numBytes += BlockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= BlockSize) + { + processBlock(current); + current += BlockSize; + m_numBytes += BlockSize; + numBytes -= BlockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process final block, less than 64 bytes +void MD5::processBuffer() +{ + // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte + + // - append "1" bit to message + // - append "0" bits until message length in bit mod 512 is 448 + // - append length as 64 bit integer + + // number of bits + size_t paddedLength = m_bufferSize * 8; + + // plus one bit set to 1 (always appended) + paddedLength++; + + // number of bits must be (numBits % 512) = 448 + size_t lower11Bits = paddedLength & 511; + if (lower11Bits <= 448) + paddedLength += 448 - lower11Bits; + else + paddedLength += 512 + 448 - lower11Bits; + // convert from bits to bytes + paddedLength /= 8; + + // only needed if additional data flows over into a second block + unsigned char extra[BlockSize]; + + // append a "1" bit, 128 => binary 10000000 + if (m_bufferSize < BlockSize) + m_buffer[m_bufferSize] = 128; + else + extra[0] = 128; + + size_t i; + for (i = m_bufferSize + 1; i < BlockSize; i++) + m_buffer[i] = 0; + for (; i < paddedLength; i++) + extra[i - BlockSize] = 0; + + // add message length in bits as 64 bit number + uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); + // find right position + unsigned char* addLength; + if (paddedLength < BlockSize) + addLength = m_buffer + paddedLength; + else + addLength = extra + paddedLength - BlockSize; + + // must be little endian + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; msgBits >>= 8; + *addLength++ = msgBits & 0xFF; + + // process blocks + processBlock(m_buffer); + // flowed over into a second block ? + if (paddedLength > BlockSize) + processBlock(extra); +} + + +/// return latest hash as 32 hex characters +std::string MD5::getHash() +{ + // compute hash (as raw bytes) + unsigned char rawHash[HashBytes]; + getHash(rawHash); + + // convert to hex string + std::string result; + result.reserve(2 * HashBytes); + for (int i = 0; i < HashBytes; i++) + { + static const char dec2hex[16+1] = "0123456789abcdef"; + result += dec2hex[(rawHash[i] >> 4) & 15]; + result += dec2hex[ rawHash[i] & 15]; + } + + return result; +} + + +/// return latest hash as bytes +void MD5::getHash(unsigned char buffer[MD5::HashBytes]) +{ + // save old hash if buffer is partially filled + uint32_t oldHash[HashValues]; + for (int i = 0; i < HashValues; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + unsigned char* current = buffer; + for (int i = 0; i < HashValues; i++) + { + *current++ = m_hash[i] & 0xFF; + *current++ = (m_hash[i] >> 8) & 0xFF; + *current++ = (m_hash[i] >> 16) & 0xFF; + *current++ = (m_hash[i] >> 24) & 0xFF; + + // restore old hash + m_hash[i] = oldHash[i]; + } +} + + +/// compute MD5 of a memory block +std::string MD5::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute MD5 of a string, excluding final zero +std::string MD5::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/tests/hashing/md5.h b/tests/hashing/md5.h new file mode 100644 index 00000000..f53e2d9e --- /dev/null +++ b/tests/hashing/md5.h @@ -0,0 +1,78 @@ +// ////////////////////////////////////////////////////////// +// md5.h +// Copyright (c) 2014 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute MD5 hash +/** Usage: + MD5 md5; + std::string myHash = md5("Hello World"); // std::string + std::string myHash2 = md5("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + MD5 md5; + while (more data available) + md5.add(pointer to fresh data, number of new bytes); + std::string myHash3 = md5.getHash(); + */ +class MD5 //: public Hash +{ +public: + /// split into 64 byte blocks (=> 512 bits), hash is 16 bytes long + enum { BlockSize = 512 / 8, HashBytes = 16 }; + + /// same as reset() + MD5(); + + /// compute MD5 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute MD5 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 32 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + /// restart + void reset(); + +private: + /// process 64 bytes + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// size of processed data in bytes + uint64_t m_numBytes; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[BlockSize]; + + enum { HashValues = HashBytes / 4 }; + /// hash, stored as integers + uint32_t m_hash[HashValues]; +}; diff --git a/tests/hashing/sha256.cpp b/tests/hashing/sha256.cpp new file mode 100644 index 00000000..0c6138cd --- /dev/null +++ b/tests/hashing/sha256.cpp @@ -0,0 +1,411 @@ +// ////////////////////////////////////////////////////////// +// sha256.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "sha256.h" + +// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN +#ifndef _MSC_VER +#include +#endif + + +/// same as reset() +SHA256::SHA256() +{ + reset(); +} + + +/// restart +void SHA256::reset() +{ + m_numBytes = 0; + m_bufferSize = 0; + + // according to RFC 1321 + m_hash[0] = 0x6a09e667; + m_hash[1] = 0xbb67ae85; + m_hash[2] = 0x3c6ef372; + m_hash[3] = 0xa54ff53a; + m_hash[4] = 0x510e527f; + m_hash[5] = 0x9b05688c; + m_hash[6] = 0x1f83d9ab; + m_hash[7] = 0x5be0cd19; +} + + +namespace +{ + inline uint32_t rotate(uint32_t a, uint32_t c) + { + return (a >> c) | (a << (32 - c)); + } + + inline uint32_t swap(uint32_t x) + { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + } + + // mix functions for processBlock() + inline uint32_t f1(uint32_t e, uint32_t f, uint32_t g) + { + uint32_t term1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25); + uint32_t term2 = (e & f) ^ (~e & g); //(g ^ (e & (f ^ g))) + return term1 + term2; + } + + inline uint32_t f2(uint32_t a, uint32_t b, uint32_t c) + { + uint32_t term1 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22); + uint32_t term2 = ((a | b) & c) | (a & b); //(a & (b ^ c)) ^ (b & c); + return term1 + term2; + } +} + + +/// process 64 bytes +void SHA256::processBlock(const void* data) +{ + // get last hash + uint32_t a = m_hash[0]; + uint32_t b = m_hash[1]; + uint32_t c = m_hash[2]; + uint32_t d = m_hash[3]; + uint32_t e = m_hash[4]; + uint32_t f = m_hash[5]; + uint32_t g = m_hash[6]; + uint32_t h = m_hash[7]; + + // data represented as 16x 32-bit words + const uint32_t* input = (uint32_t*) data; + // convert to big endian + uint32_t words[64]; + int i; + for (i = 0; i < 16; i++) +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) + words[i] = input[i]; +#else + words[i] = swap(input[i]); +#endif + + uint32_t x,y; // temporaries + + // first round + x = h + f1(e,f,g) + 0x428a2f98 + words[ 0]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x71374491 + words[ 1]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0xb5c0fbcf + words[ 2]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0xe9b5dba5 + words[ 3]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x3956c25b + words[ 4]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x59f111f1 + words[ 5]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x923f82a4 + words[ 6]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0xab1c5ed5 + words[ 7]; y = f2(b,c,d); e += x; a = x + y; + + // secound round + x = h + f1(e,f,g) + 0xd807aa98 + words[ 8]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x12835b01 + words[ 9]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x243185be + words[10]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x550c7dc3 + words[11]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x72be5d74 + words[12]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x80deb1fe + words[13]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x9bdc06a7 + words[14]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0xc19bf174 + words[15]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 24 words + for (; i < 24; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // third round + x = h + f1(e,f,g) + 0xe49b69c1 + words[16]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0xefbe4786 + words[17]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x0fc19dc6 + words[18]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x240ca1cc + words[19]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x2de92c6f + words[20]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x4a7484aa + words[21]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x5cb0a9dc + words[22]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x76f988da + words[23]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 32 words + for (; i < 32; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // fourth round + x = h + f1(e,f,g) + 0x983e5152 + words[24]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0xa831c66d + words[25]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0xb00327c8 + words[26]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0xbf597fc7 + words[27]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0xc6e00bf3 + words[28]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0xd5a79147 + words[29]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x06ca6351 + words[30]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x14292967 + words[31]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 40 words + for (; i < 40; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // fifth round + x = h + f1(e,f,g) + 0x27b70a85 + words[32]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x2e1b2138 + words[33]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x4d2c6dfc + words[34]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x53380d13 + words[35]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x650a7354 + words[36]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x766a0abb + words[37]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x81c2c92e + words[38]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x92722c85 + words[39]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 48 words + for (; i < 48; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // sixth round + x = h + f1(e,f,g) + 0xa2bfe8a1 + words[40]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0xa81a664b + words[41]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0xc24b8b70 + words[42]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0xc76c51a3 + words[43]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0xd192e819 + words[44]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0xd6990624 + words[45]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0xf40e3585 + words[46]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x106aa070 + words[47]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 56 words + for (; i < 56; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // seventh round + x = h + f1(e,f,g) + 0x19a4c116 + words[48]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x1e376c08 + words[49]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x2748774c + words[50]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x34b0bcb5 + words[51]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x391c0cb3 + words[52]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0x4ed8aa4a + words[53]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0x5b9cca4f + words[54]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0x682e6ff3 + words[55]; y = f2(b,c,d); e += x; a = x + y; + + // extend to 64 words + for (; i < 64; i++) + words[i] = words[i-16] + + (rotate(words[i-15], 7) ^ rotate(words[i-15], 18) ^ (words[i-15] >> 3)) + + words[i-7] + + (rotate(words[i- 2], 17) ^ rotate(words[i- 2], 19) ^ (words[i- 2] >> 10)); + + // eigth round + x = h + f1(e,f,g) + 0x748f82ee + words[56]; y = f2(a,b,c); d += x; h = x + y; + x = g + f1(d,e,f) + 0x78a5636f + words[57]; y = f2(h,a,b); c += x; g = x + y; + x = f + f1(c,d,e) + 0x84c87814 + words[58]; y = f2(g,h,a); b += x; f = x + y; + x = e + f1(b,c,d) + 0x8cc70208 + words[59]; y = f2(f,g,h); a += x; e = x + y; + x = d + f1(a,b,c) + 0x90befffa + words[60]; y = f2(e,f,g); h += x; d = x + y; + x = c + f1(h,a,b) + 0xa4506ceb + words[61]; y = f2(d,e,f); g += x; c = x + y; + x = b + f1(g,h,a) + 0xbef9a3f7 + words[62]; y = f2(c,d,e); f += x; b = x + y; + x = a + f1(f,g,h) + 0xc67178f2 + words[63]; y = f2(b,c,d); e += x; a = x + y; + + // update hash + m_hash[0] += a; + m_hash[1] += b; + m_hash[2] += c; + m_hash[3] += d; + m_hash[4] += e; + m_hash[5] += f; + m_hash[6] += g; + m_hash[7] += h; +} + + +/// add arbitrary number of bytes +void SHA256::add(const void* data, size_t numBytes) +{ + const uint8_t* current = (const uint8_t*) data; + + if (m_bufferSize > 0) + { + while (numBytes > 0 && m_bufferSize < BlockSize) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == BlockSize) + { + processBlock(m_buffer); + m_numBytes += BlockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) + return; + + // process full blocks + while (numBytes >= BlockSize) + { + processBlock(current); + current += BlockSize; + m_numBytes += BlockSize; + numBytes -= BlockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) + { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + + +/// process final block, less than 64 bytes +void SHA256::processBuffer() +{ + // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte + + // - append "1" bit to message + // - append "0" bits until message length in bit mod 512 is 448 + // - append length as 64 bit integer + + // number of bits + size_t paddedLength = m_bufferSize * 8; + + // plus one bit set to 1 (always appended) + paddedLength++; + + // number of bits must be (numBits % 512) = 448 + size_t lower11Bits = paddedLength & 511; + if (lower11Bits <= 448) + paddedLength += 448 - lower11Bits; + else + paddedLength += 512 + 448 - lower11Bits; + // convert from bits to bytes + paddedLength /= 8; + + // only needed if additional data flows over into a second block + unsigned char extra[BlockSize]; + + // append a "1" bit, 128 => binary 10000000 + if (m_bufferSize < BlockSize) + m_buffer[m_bufferSize] = 128; + else + extra[0] = 128; + + size_t i; + for (i = m_bufferSize + 1; i < BlockSize; i++) + m_buffer[i] = 0; + for (; i < paddedLength; i++) + extra[i - BlockSize] = 0; + + // add message length in bits as 64 bit number + uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); + // find right position + unsigned char* addLength; + if (paddedLength < BlockSize) + addLength = m_buffer + paddedLength; + else + addLength = extra + paddedLength - BlockSize; + + // must be big endian + *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF); + *addLength = (unsigned char)( msgBits & 0xFF); + + // process blocks + processBlock(m_buffer); + // flowed over into a second block ? + if (paddedLength > BlockSize) + processBlock(extra); +} + + +/// return latest hash as 64 hex characters +std::string SHA256::getHash() +{ + // compute hash (as raw bytes) + unsigned char rawHash[HashBytes]; + getHash(rawHash); + + // convert to hex string + std::string result; + result.reserve(2 * HashBytes); + for (int i = 0; i < HashBytes; i++) + { + static const char dec2hex[16+1] = "0123456789abcdef"; + result += dec2hex[(rawHash[i] >> 4) & 15]; + result += dec2hex[ rawHash[i] & 15]; + } + + return result; +} + + +/// return latest hash as bytes +void SHA256::getHash(unsigned char buffer[SHA256::HashBytes]) +{ + // save old hash if buffer is partially filled + uint32_t oldHash[HashValues]; + for (int i = 0; i < HashValues; i++) + oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + unsigned char* current = buffer; + for (int i = 0; i < HashValues; i++) + { + *current++ = (m_hash[i] >> 24) & 0xFF; + *current++ = (m_hash[i] >> 16) & 0xFF; + *current++ = (m_hash[i] >> 8) & 0xFF; + *current++ = m_hash[i] & 0xFF; + + // restore old hash + m_hash[i] = oldHash[i]; + } +} + + +/// compute SHA256 of a memory block +std::string SHA256::operator()(const void* data, size_t numBytes) +{ + reset(); + add(data, numBytes); + return getHash(); +} + + +/// compute SHA256 of a string, excluding final zero +std::string SHA256::operator()(const std::string& text) +{ + reset(); + add(text.c_str(), text.size()); + return getHash(); +} diff --git a/tests/hashing/sha256.h b/tests/hashing/sha256.h new file mode 100644 index 00000000..aeaf314f --- /dev/null +++ b/tests/hashing/sha256.h @@ -0,0 +1,78 @@ +// ////////////////////////////////////////////////////////// +// sha256.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#pragma once + +//#include "hash.h" +#include + +// define fixed size integer types +#ifdef _MSC_VER +// Windows +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +// GCC +#include +#endif + + +/// compute SHA256 hash +/** Usage: + SHA256 sha256; + std::string myHash = sha256("Hello World"); // std::string + std::string myHash2 = sha256("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + SHA256 sha256; + while (more data available) + sha256.add(pointer to fresh data, number of new bytes); + std::string myHash3 = sha256.getHash(); + */ +class SHA256 //: public Hash +{ +public: + /// split into 64 byte blocks (=> 512 bits), hash is 32 bytes long + enum { BlockSize = 512 / 8, HashBytes = 32 }; + + /// same as reset() + SHA256(); + + /// compute SHA256 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute SHA256 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 64 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + /// restart + void reset(); + +private: + /// process 64 bytes + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// size of processed data in bytes + uint64_t m_numBytes; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[BlockSize]; + + enum { HashValues = HashBytes / 4 }; + /// hash, stored as integers + uint32_t m_hash[HashValues]; +}; diff --git a/tests/unit/map2/map_defs.h b/tests/unit/map2/map_defs.h index 47c17bbe..644f9cb6 100644 --- a/tests/unit/map2/map_defs.h +++ b/tests/unit/map2/map_defs.h @@ -727,12 +727,45 @@ TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_stdhash) \ TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_stdhash_stat) \ TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_stdhash) \ - TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_stdhash_stat) + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_stdhash_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_md5) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_md5_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_md5) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_md5_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_sha256) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_sha256_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_sha256) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_sha256_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city64) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city64_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city64) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city64_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city128) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city128_stat) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city128) \ + TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city128_stat) \ + #undef CDSUNIT_TEST_MultiLevelHashMap #define CDSUNIT_TEST_MultiLevelHashMap \ CPPUNIT_TEST(MultiLevelHashMap_hp_stdhash) \ CPPUNIT_TEST(MultiLevelHashMap_hp_stdhash_stat) \ CPPUNIT_TEST(MultiLevelHashMap_dhp_stdhash) \ - CPPUNIT_TEST(MultiLevelHashMap_dhp_stdhash_stat) + CPPUNIT_TEST(MultiLevelHashMap_dhp_stdhash_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_md5) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_md5_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_md5) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_md5_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_sha256) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_sha256_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_sha256) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_sha256_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_city64) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_city64_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_city64) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_city64_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_city128) \ + CPPUNIT_TEST(MultiLevelHashMap_hp_city128_stat) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_city128) \ + CPPUNIT_TEST(MultiLevelHashMap_dhp_city128_stat) \ diff --git a/tests/unit/map2/map_type_multilevel_hashmap.h b/tests/unit/map2/map_type_multilevel_hashmap.h index 2c25a8e9..307ebc1a 100644 --- a/tests/unit/map2/map_type_multilevel_hashmap.h +++ b/tests/unit/map2/map_type_multilevel_hashmap.h @@ -9,6 +9,7 @@ #include #include "print_multilevel_hashset_stat.h" +#include "hashing/hash_func.h" namespace map2 { @@ -46,6 +47,66 @@ namespace map2 { typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_stat > MultiLevelHashMap_hp_stdhash_stat; typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_stat > MultiLevelHashMap_dhp_stdhash_stat; + + // SHA256 + struct traits_MultiLevelHashMap_sha256 : public cc::multilevel_hashmap::traits + { + typedef ::hashing::sha256 hash; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_sha256 > MultiLevelHashMap_hp_sha256; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_sha256 > MultiLevelHashMap_dhp_sha256; + + struct traits_MultiLevelHashMap_sha256_stat : public traits_MultiLevelHashMap_sha256 + { + typedef cc::multilevel_hashmap::stat<> stat; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_sha256_stat > MultiLevelHashMap_hp_sha256_stat; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_sha256_stat > MultiLevelHashMap_dhp_sha256_stat; + + //MD5 + struct traits_MultiLevelHashMap_md5 : public cc::multilevel_hashmap::traits + { + typedef ::hashing::md5 hash; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_md5 > MultiLevelHashMap_hp_md5; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_md5 > MultiLevelHashMap_dhp_md5; + + struct traits_MultiLevelHashMap_md5_stat : public traits_MultiLevelHashMap_md5 + { + typedef cc::multilevel_hashmap::stat<> stat; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_md5_stat > MultiLevelHashMap_hp_md5_stat; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_md5_stat > MultiLevelHashMap_dhp_md5_stat; + + // CityHash + struct traits_MultiLevelHashMap_city64 : public cc::multilevel_hashmap::traits + { + typedef ::hashing::city64 hash; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_city64 > MultiLevelHashMap_hp_city64; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city64 > MultiLevelHashMap_dhp_city64; + + struct traits_MultiLevelHashMap_city64_stat : public traits_MultiLevelHashMap_city64 + { + typedef cc::multilevel_hashmap::stat<> stat; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_city64_stat > MultiLevelHashMap_hp_city64_stat; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city64_stat > MultiLevelHashMap_dhp_city64_stat; + + struct traits_MultiLevelHashMap_city128 : public cc::multilevel_hashmap::traits + { + typedef ::hashing::city128 hash; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_city128 > MultiLevelHashMap_hp_city128; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city128 > MultiLevelHashMap_dhp_city128; + + struct traits_MultiLevelHashMap_city128_stat : public traits_MultiLevelHashMap_city128 + { + typedef cc::multilevel_hashmap::stat<> stat; + }; + typedef MultiLevelHashMap< cds::gc::HP, Key, Value, traits_MultiLevelHashMap_city128_stat > MultiLevelHashMap_hp_city128_stat; + typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city128_stat > MultiLevelHashMap_dhp_city128_stat; + }; template