1 module vayne.hash; 2 3 4 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (is(T == enum)) { 5 return hashOf(cast(EType)x, seed); 6 } 7 8 9 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && __traits(isStaticArray, T)) { 10 auto hash = seed; 11 foreach (ref e; x) 12 hash = hashOf(e, hash); 13 return hash; 14 } 15 16 17 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStaticArray, T) && !is(T == struct) && !is(T == class) && !is(T == union)) { 18 alias ElementType = typeof(x[0]); 19 20 static if (is(ElementType == interface) || is(ElementType == class) || ((is(ElementType == struct) || is(ElementType == union)) && is(typeof(x[0].toHash()) == size_t))) { 21 auto hash = seed; 22 foreach (o; x) 23 hash = hashOf(o, hash); 24 return hash; 25 } else { 26 return hash(x.ptr, ElementType.sizeof * x.length, seed); 27 } 28 } 29 30 31 @trusted nothrow pure 32 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T)) { 33 static if(__traits(isFloating, x)) { 34 T y = (x != x) ? T.nan : x; 35 return hash(cast(ubyte*)&y, T.sizeof, seed); 36 } else { 37 return hash(cast(ubyte*)&x, T.sizeof, seed); 38 } 39 } 40 41 42 @trusted nothrow pure 43 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && is(T : typeof(null))) { 44 return hashOf(cast(void*)null); 45 } 46 47 48 @trusted nothrow pure 49 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && is(T V : V*) && !is(T : typeof(null)) && !is(T == struct) && !is(T == class) && !is(T == union)) { 50 return hashOf(cast(size_t)x); 51 } 52 53 54 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && (is(T == struct) || is(T == union))) { 55 static if (is(typeof(x.toHash()) == size_t)) { 56 return hashOf(x.toHash(), seed); 57 } else { 58 return hash(cast(ubyte*)&x, T.sizeof, seed); 59 } 60 } 61 62 63 @trusted nothrow pure 64 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && is(T == delegate)) { 65 return hash(cast(ubyte*)&x, T.sizeof, seed); 66 } 67 68 69 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && is(T == interface) || is(T == class)) { 70 return hashOf(x ? (cast(Object)x).toHash() : 0, seed); 71 } 72 73 74 hash_t hashOf(T)(auto ref T x, size_t seed = 0) if (!is(T == enum) && __traits(isAssociativeArray, T)) { 75 if (!x.length) 76 return hashOf(0, seed); 77 78 size_t h = 0; 79 foreach (k, ref v; x) { 80 size_t[2] hpair; 81 hpair[0] = k.hashOf(); 82 hpair[1] = v.hashOf(); 83 h ^= hpair.hashOf(); 84 } 85 return h.hashOf(seed); 86 } 87 88 89 @trusted nothrow pure 90 hash_t hash(T)(in const(T)* x, size_t len, size_t seed = 0) { 91 version(X86_64) { 92 return hash64(x, len, seed); 93 } else { 94 return hash32(x, len, seed); 95 } 96 } 97 98 99 @trusted nothrow pure 100 uint hash32(T)(in const(T)* x, size_t len, uint seed = 0) if (__traits(isArithmetic, T) && (T.sizeof == 1)) { 101 uint h = cast(uint)len; 102 const(ubyte)* p = cast(const(ubyte)*)x; 103 const(ubyte)* end = p + len; 104 105 if (len >= 16) { 106 const const(ubyte)* limit = p + (len - 16); 107 uint v1 = seed + Prime32_1 + Prime32_2; 108 uint v2 = seed + Prime32_2; 109 uint v3 = seed + 0; 110 uint v4 = seed - Prime32_1; 111 112 do { 113 v1 += read32(p) * Prime32_2; v1 = rotl32!13(v1); v1 *= Prime32_1; p += 4; 114 v2 += read32(p) * Prime32_2; v2 = rotl32!13(v2); v2 *= Prime32_1; p += 4; 115 v3 += read32(p) * Prime32_2; v3 = rotl32!13(v3); v3 *= Prime32_1; p += 4; 116 v4 += read32(p) * Prime32_2; v4 = rotl32!13(v4); v4 *= Prime32_1; p += 4; 117 } while (p <= limit); 118 119 h += rotl32!1(v1) + rotl32!7(v2) + rotl32!12(v3) + rotl32!18(v4); 120 } else { 121 h += seed + Prime32_5; 122 } 123 124 while ((p + 4) <= end) { 125 h += read32(p) * Prime32_3; 126 h = rotl32!17(h) * Prime32_4; 127 p += 4; 128 } 129 130 while (p != end) { 131 h += (*p) * Prime32_5; 132 h = rotl32!11(h) * Prime32_1; 133 ++p; 134 } 135 136 h ^= h >> 15; 137 h *= Prime32_2; 138 h ^= h >> 13; 139 h *= Prime32_3; 140 h ^= h >> 16; 141 return h; 142 } 143 144 145 @trusted nothrow pure 146 ulong hash64(T)(in const(T)* x, size_t len, ulong seed = 0) if (__traits(isArithmetic, T) && (T.sizeof == 1)) { 147 ulong h = len; 148 const(ubyte)* p = cast(const(ubyte)*)x; 149 const(ubyte)* end = p + len; 150 151 if (len >= 32) { 152 const const(ubyte)* limit = p + (len - 32); 153 ulong v1 = seed + Prime64_1 + Prime64_2; 154 ulong v2 = seed + Prime64_2; 155 ulong v3 = seed + 0; 156 ulong v4 = seed - Prime64_1; 157 158 do { 159 v1 += read64(p) * Prime64_2; v1 = rotl64!31(v1); v1 *= Prime64_1; p += 8; 160 v2 += read64(p) * Prime64_2; v2 = rotl64!31(v2); v2 *= Prime64_1; p += 8; 161 v3 += read64(p) * Prime64_2; v3 = rotl64!31(v3); v3 *= Prime64_1; p += 8; 162 v4 += read64(p) * Prime64_2; v4 = rotl64!31(v4); v4 *= Prime64_1; p += 8; 163 } while (p <= limit); 164 165 h += rotl64!1(v1) + rotl64!7(v2) + rotl64!12(v3) + rotl64!18(v4); 166 167 v1 *= Prime64_2; v1 = rotl64!31(v1); v1 *= Prime64_1; h ^= v1; 168 h = h * Prime64_1 + Prime64_4; 169 170 v2 *= Prime64_2; v2 = rotl64!31(v2); v2 *= Prime64_1; h ^= v2; 171 h = h * Prime64_1 + Prime64_4; 172 173 v3 *= Prime64_2; v3 = rotl64!31(v3); v3 *= Prime64_1; h ^= v3; 174 h = h * Prime64_1 + Prime64_4; 175 176 v4 *= Prime64_2; v4 = rotl64!31(v4); v4 *= Prime64_1; h ^= v4; 177 h = h * Prime64_1 + Prime64_4; 178 } else { 179 h += seed + Prime64_5; 180 } 181 182 while ((p + 8) <= end) { 183 ulong k = read64(p); 184 k *= Prime64_2; k = rotl64!31(k); k *= Prime64_1; h ^= k; 185 h = rotl64!27(h) * Prime64_1 + Prime64_4; 186 p += 8; 187 } 188 189 while ((p + 4) <= end) { 190 h ^= read32(p) * Prime64_1; 191 h = rotl64!23(h) * Prime32_2 + Prime64_3; 192 p += 4; 193 } 194 195 while (p != end) { 196 h ^= (*p) * Prime64_5; 197 h = rotl64!11(h) * Prime32_1; 198 ++p; 199 } 200 201 h ^= h >> 33; 202 h *= Prime64_2; 203 h ^= h >> 29; 204 h *= Prime64_3; 205 h ^= h >> 32; 206 return h; 207 } 208 209 210 private { 211 enum : uint { 212 Prime32_1 = 2654435761U, 213 Prime32_2 = 2246822519U, 214 Prime32_3 = 3266489917U, 215 Prime32_4 = 668265263U, 216 Prime32_5 = 374761393U, 217 } 218 219 uint rotl32(size_t K)(in uint x) nothrow pure { 220 return (x << K) | (x >> (32 - K)); 221 } 222 223 uint read32(const ubyte* p) nothrow pure { 224 return *cast(uint*)p; 225 } 226 227 enum : ulong { 228 Prime64_1 = 11400714785074694791UL, 229 Prime64_2 = 14029467366897019727UL, 230 Prime64_3 = 1609587929392839161UL, 231 Prime64_4 = 9650029242287828579UL, 232 Prime64_5 = 2870177450012600261UL, 233 } 234 235 ulong rotl64(size_t K)(in ulong x) nothrow pure { 236 return (cast(ulong)x << K) | (cast(ulong)x >> (64 - K)); 237 } 238 239 ulong read64(const ubyte* p) nothrow pure { 240 return *cast(ulong*)p; 241 } 242 }