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 }