1 /**
2  * Written in the D programming language.
3  * This module provides functions to uniform calculating hash values for different types
4  *
5  * Copyright: Copyright Igor Stepanov 2013-2013.
6  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
7  * Authors:   Igor Stepanov
8  * Source: $(DRUNTIMESRC core/internal/_hash.d)
9  */
10 module core.internal.hash;
11 
12 import core.internal.traits : Unconst;
13 
14 // If true ensure that positive zero and negative zero have the same hash.
15 // Historically typeid(float).getHash did this but hashOf(float) did not.
16 private enum floatCoalesceZeroes = true;
17 // If true ensure that all NaNs of the same floating point type have the same hash.
18 // Historically typeid(float).getHash didn't do this but hashOf(float) did.
19 private enum floatCoalesceNaNs = true;
20 
21 // If either of the above are true then no struct or array that contains the
22 // representation of a floating point number may be hashed with `bytesHash`.
23 
24 @nogc nothrow pure @safe unittest
25 {
26     static if (floatCoalesceZeroes)
27         assert(hashOf(+0.0) == hashOf(-0.0)); // Same hash for +0.0 and -0.0.
28     static if (floatCoalesceNaNs)
29         assert(hashOf(double.nan) == hashOf(-double.nan)); // Same hash for different NaN.
30 }
31 
32 private enum hasCallableToHash(T) = __traits(compiles,
33     {
34         size_t hash = ((T* x) => (*x).toHash())(null);
35     });
36 
37 @nogc nothrow pure @safe unittest
38 {
39     static struct S { size_t toHash() { return 4; } }
40     assert(hasCallableToHash!S);
41     assert(!hasCallableToHash!(shared const S));
42 }
43 
44 private enum isFinalClassWithAddressBasedHash(T) = __traits(isFinalClass, T)
45     // Use __traits(compiles, ...) in case there are multiple overloads of `toHash`.
46     && __traits(compiles, {static assert(&Object.toHash is &T.toHash);});
47 
48 @nogc nothrow pure @safe unittest
49 {
50     static class C1 {}
51     final static class C2 : C1 {}
52     final static class C3 : C1 { override size_t toHash() const nothrow { return 1; }}
53     static assert(!isFinalClassWithAddressBasedHash!Object);
54     static assert(!isFinalClassWithAddressBasedHash!C1);
55     static assert(isFinalClassWithAddressBasedHash!C2);
56     static assert(!isFinalClassWithAddressBasedHash!C3);
57 }
58 
59 private template isCppClassWithoutHash(T)
60 {
61     static if (!is(T == class) && !is(T == interface))
62         enum isCppClassWithoutHash = false;
63     else
64         enum bool isCppClassWithoutHash = __traits(getLinkage, T) == "C++"
65             && !is(immutable T* : immutable Object*) && !hasCallableToHash!T;
66 }
67 
68 /+
69 Is it valid to calculate a hash code for T based on the bits of its
70 representation? Always false for interfaces, dynamic arrays, and
71 associative arrays. False for all classes except final classes that do
72 not override `toHash`.
73 
74 Note: according to the spec as of
75 https://github.com/dlang/dlang.org/commit/d66eff16491b0664c0fc00ba80a7aa291703f1f2
76 the contents of unnamed paddings between fields is undefined. Currently
77 this hashing implementation assumes that the padding contents (if any)
78 for all instances of `T` are the same. The correctness of this
79 assumption is yet to be verified.
80 +/
81 private template canBitwiseHash(T)
82 {
83     static if (is(T EType == enum))
84         enum canBitwiseHash = .canBitwiseHash!EType;
85     else static if (__traits(isFloating, T))
86         enum canBitwiseHash = !(floatCoalesceZeroes || floatCoalesceNaNs);
87     else static if (__traits(isScalar, T))
88         enum canBitwiseHash = true;
89     else static if (is(T == class))
90     {
91         enum canBitwiseHash = isFinalClassWithAddressBasedHash!T || isCppClassWithoutHash!T;
92     }
93     else static if (is(T == interface))
94     {
95         enum canBitwiseHash = isCppClassWithoutHash!T;
96     }
97     else static if (is(T == struct))
98     {
99         static if (hasCallableToHash!T || __traits(isNested, T))
100             enum canBitwiseHash = false;
101         else
102         {
103             import core.internal.traits : allSatisfy;
104             enum canBitwiseHash = allSatisfy!(.canBitwiseHash, typeof(T.tupleof));
105         }
106     }
107     else static if (is(T == union))
108     {
109         // Right now we always bytewise hash unions that lack callable `toHash`.
110         enum canBitwiseHash = !hasCallableToHash!T;
111     }
112     else static if (is(T E : E[]))
113     {
114         static if (__traits(isStaticArray, T))
115             enum canBitwiseHash = (T.length == 0) || .canBitwiseHash!E;
116         else
117             enum canBitwiseHash = false;
118     }
119     else static if (__traits(isAssociativeArray, T))
120     {
121         enum canBitwiseHash = false;
122     }
123     else
124     {
125         static assert(is(T == delegate) || is(T : void) || is(T : typeof(null)),
126             "Internal error: unanticipated type "~T.stringof);
127         enum canBitwiseHash = true;
128     }
129 }
130 
131 //enum hash. CTFE depends on base type
132 size_t hashOf(T)(auto ref T val, size_t seed = 0)
133 if (is(T == enum) && !__traits(isScalar, T))
134 {
135     static if (is(T EType == enum)) {} //for EType
136     return hashOf(cast(EType) val, seed);
137 }
138 
139 //CTFE ready (depends on base type).
140 size_t hashOf(T)(scope const auto ref T val, size_t seed = 0)
141 if (!is(T == enum) && __traits(isStaticArray, T) && canBitwiseHash!T)
142 {
143     import core.internal.convert : toUbyte;
144     // FIXME:
145     // We would like to to do this:
146     //
147     //static if (T.length == 0)
148     //    return seed;
149     //else static if (T.length == 1)
150     //    return hashOf(val[0], seed);
151     //else
152     //    return bytesHashWithExactSizeAndAlignment!T(toUbyte(val), seed);
153     //
154     // ... but that's inefficient when using a runtime TypeInfo (introduces a branch)
155     // and PR #2243 wants typeid(T).getHash(&val) to produce the same result as
156     // hashOf(val).
157     static if (T.length == 0)
158     {
159         return bytesHashAlignedBy!size_t((ubyte[]).init, seed);
160     }
161     static if (is(typeof(toUbyte(val)) == const(ubyte)[]))
162     {
163         return bytesHashAlignedBy!T(toUbyte(val), seed);
164     }
165     else //Other types. CTFE unsupported
166     {
167         assert(!__ctfe, "unable to compute hash of "~T.stringof~" at compile time");
168         return bytesHashAlignedBy!T((cast(const(ubyte)*) &val)[0 .. T.sizeof], seed);
169     }
170 }
171 
172 //CTFE ready (depends on base type).
173 size_t hashOf(T)(auto ref T val, size_t seed = 0)
174 if (!is(T == enum) && __traits(isStaticArray, T) && !canBitwiseHash!T)
175 {
176     // FIXME:
177     // We would like to to do this:
178     //
179     //static if (T.length == 0)
180     //    return seed;
181     //else static if (T.length == 1)
182     //    return hashOf(val[0], seed);
183     //else
184     //    /+ hash like a dynamic array +/
185     //
186     // ... but that's inefficient when using a runtime TypeInfo (introduces a branch)
187     // and PR #2243 wants typeid(T).getHash(&val) to produce the same result as
188     // hashOf(val).
189     return hashOf(val[], seed);
190 }
191 
192 //dynamic array hash
193 size_t hashOf(T)(scope const T val, size_t seed = 0)
194 if (is(T == S[], S) && (__traits(isScalar, S) || canBitwiseHash!S)) // excludes enum types
195 {
196     import core.internal.convert : toUbyte;
197     alias ElementType = typeof(val[0]);
198     static if (!canBitwiseHash!ElementType)
199     {
200         size_t hash = seed;
201         foreach (ref o; val)
202         {
203             hash = hashOf(hashOf(o), hash); // double hashing to match TypeInfo.getHash
204         }
205         return hash;
206     }
207     else static if (is(typeof(toUbyte(val)) == const(ubyte)[]))
208     //ubyteble array (arithmetic types and structs without toHash) CTFE ready for arithmetic types and structs without reference fields
209     {
210         return bytesHashAlignedBy!ElementType(toUbyte(val), seed);
211     }
212     else //Other types. CTFE unsupported
213     {
214         assert(!__ctfe, "unable to compute hash of "~T.stringof~" at compile time");
215         return bytesHashAlignedBy!ElementType((cast(const(ubyte)*) val.ptr)[0 .. ElementType.sizeof*val.length], seed);
216     }
217 }
218 
219 //dynamic array hash
220 size_t hashOf(T)(T val, size_t seed = 0)
221 if (is(T == S[], S) && !(__traits(isScalar, S) || canBitwiseHash!S)) // excludes enum types
222 {
223     size_t hash = seed;
224     foreach (ref o; val)
225     {
226         hash = hashOf(hashOf(o), hash); // double hashing because TypeInfo.getHash doesn't allow to pass seed value
227     }
228     return hash;
229 }
230 
231 // Indicates if F is a built-in complex number type.
232 private F coalesceFloat(F)(const F val)
233 if (__traits(isFloating, val) && !is(F == __vector) && !is(F : creal))
234 {
235     static if (floatCoalesceZeroes)
236         if (val == cast(F) 0)
237             return cast(F) 0;
238     static if (floatCoalesceNaNs)
239         if (val != val)
240             return F.nan;
241     return val;
242 }
243 
244 //scalar type hash
245 @trusted @nogc nothrow pure
246 size_t hashOf(T)(scope const T val) if (__traits(isScalar, T) && !is(T == __vector))
247 {
248     static if (is(T V : V*))
249     {
250         if (__ctfe)
251         {
252             if (val is null) return 0;
253             assert(0, "Unable to calculate hash of non-null pointer at compile time");
254         }
255         size_t result = cast(size_t) val;
256         return result ^ (result >> 4);
257     }
258     else static if (is(T EType == enum) && is(typeof(val[0])))
259     {
260         // Enum type whose base type is vector.
261         return hashOf(cast(EType) val);
262     }
263     else static if (__traits(isIntegral, T))
264     {
265         static if (T.sizeof <= size_t.sizeof)
266             return val;
267         else
268             return cast(size_t) (val ^ (val >>> (size_t.sizeof * 8)));
269     }
270     else static if (is(T : creal))
271     {
272         return hashOf(coalesceFloat(val.re), hashOf(coalesceFloat(val.im)));
273     }
274     else
275     {
276         static assert(__traits(isFloating, T));
277         auto data = coalesceFloat(val);
278         static if (T.sizeof == float.sizeof && T.mant_dig == float.mant_dig)
279             return *cast(const uint*) &data;
280         else static if (T.sizeof == double.sizeof && T.mant_dig == double.mant_dig)
281             return hashOf(*cast(const ulong*) &data);
282         else
283         {
284             import core.internal.convert : floatSize, toUbyte;
285             return bytesHashWithExactSizeAndAlignment!T(toUbyte(data)[0 .. floatSize!T], 0);
286         }
287     }
288 }
289 
290 //scalar type hash
291 @trusted @nogc nothrow pure
292 size_t hashOf(T)(scope const T val, size_t seed) if (__traits(isScalar, T) && !is(T == __vector))
293 {
294     static if (is(T V : V*))
295     {
296         if (__ctfe)
297         {
298             if (val is null) return hashOf(size_t(0), seed);
299             assert(0, "Unable to calculate hash of non-null pointer at compile time");
300         }
301         return hashOf(cast(size_t) val, seed);
302     }
303     else static if (is(T EType == enum) && is(typeof(val[0])))
304     {
305         // Enum type whose base type is vector.
306         return hashOf(cast(EType) val, seed);
307     }
308     else static if (__traits(isIntegral, val) && T.sizeof <= size_t.sizeof)
309     {
310         static if (size_t.sizeof < ulong.sizeof)
311         {
312             //MurmurHash3 32-bit single round
313             enum uint c1 = 0xcc9e2d51;
314             enum uint c2 = 0x1b873593;
315             enum uint c3 = 0xe6546b64;
316             enum uint r1 = 15;
317             enum uint r2 = 13;
318         }
319         else
320         {
321             //Half of MurmurHash3 64-bit single round
322             //(omits second interleaved update)
323             enum ulong c1 = 0x87c37b91114253d5;
324             enum ulong c2 = 0x4cf5ad432745937f;
325             enum ulong c3 = 0x52dce729;
326             enum uint r1 = 31;
327             enum uint r2 = 27;
328         }
329         size_t h = c1 * val;
330         h = (h << r1) | (h >>> (size_t.sizeof * 8 - r1));
331         h = (h * c2) ^ seed;
332         h = (h << r2) | (h >>> (size_t.sizeof * 8 - r2));
333         return h * 5 + c3;
334     }
335     else static if (__traits(isIntegral, val) && T.sizeof > size_t.sizeof)
336     {
337         static foreach (i; 0 .. T.sizeof / size_t.sizeof)
338             seed = hashOf(cast(size_t) (val >>> (size_t.sizeof * 8 * i)), seed);
339         return seed;
340     }
341     else static if (is(T : creal))
342     {
343         return hashOf(val.re, hashOf(val.im, seed));
344     }
345     else static if (__traits(isFloating, T))
346     {
347         auto data = coalesceFloat(val);
348         static if (T.sizeof == float.sizeof && T.mant_dig == float.mant_dig)
349             return hashOf(*cast(const uint*) &data, seed);
350         else static if (T.sizeof == double.sizeof && T.mant_dig == double.mant_dig)
351             return hashOf(*cast(const ulong*) &data, seed);
352         else
353         {
354             import core.internal.convert : floatSize, toUbyte;
355             return bytesHashWithExactSizeAndAlignment!T(toUbyte(data)[0 .. floatSize!T], seed);
356         }
357     }
358     else
359     {
360         static assert(0);
361     }
362 }
363 
364 size_t hashOf(T)(scope const T val, size_t seed = 0) @safe @nogc nothrow pure
365 if (is(T == __vector)) // excludes enum types
366 {
367     static if (__traits(isFloating, T) && (floatCoalesceZeroes || floatCoalesceNaNs))
368     {
369         if (__ctfe)
370         {
371             // Workaround for CTFE bug.
372             static if (is(immutable typeof(val[0]) == immutable E, E)) {} // Get E.
373             E[T.sizeof / E.sizeof] array;
374             foreach (i; 0 .. T.sizeof / E.sizeof)
375                 array[i] = val[i];
376             return hashOf(array, seed);
377         }
378         return hashOf(val.array, seed);
379     }
380     else
381     {
382         import core.internal.convert : toUbyte;
383         return bytesHashAlignedBy!T(toUbyte(val), seed);
384     }
385 }
386 
387 //typeof(null) hash. CTFE supported
388 @trusted @nogc nothrow pure
389 size_t hashOf(T)(scope const T val) if (!is(T == enum) && is(T : typeof(null)))
390 {
391     return 0;
392 }
393 
394 //typeof(null) hash. CTFE supported
395 @trusted @nogc nothrow pure
396 size_t hashOf(T)(scope const T val, size_t seed) if (!is(T == enum) && is(T : typeof(null)))
397 {
398     return hashOf(size_t(0), seed);
399 }
400 
401 private enum _hashOfStruct =
402 q{
403     enum bool isChained = is(typeof(seed) : size_t);
404     static if (!isChained) enum size_t seed = 0;
405     static if (hasCallableToHash!(typeof(val))) //CTFE depends on toHash()
406     {
407         static if (!__traits(isSame, typeof(val), __traits(parent, val.toHash))
408             && is(typeof(val is null)))
409         {
410             static if (isChained)
411                 return hashOf(__traits(getMember, val, __traits(getAliasThis, typeof(val))), seed);
412             else
413                 return hashOf(__traits(getMember, val, __traits(getAliasThis, typeof(val))));
414         }
415         else
416         {
417             static if (isChained)
418                 return hashOf(cast(size_t) val.toHash(), seed);
419             else
420                 return val.toHash();
421         }
422     }
423     else
424     {
425         import core.internal.convert : toUbyte;
426         static if (__traits(hasMember, T, "toHash") && is(typeof(T.toHash) == function))
427         {
428             // TODO: in the future maybe this should be changed to a static
429             // assert(0), because if there's a `toHash` the programmer probably
430             // expected it to be called and a compilation failure here will
431             // expose a bug in his code.
432             //   In the future we also might want to disallow non-const toHash
433             // altogether.
434             pragma(msg, "Warning: struct "~__traits(identifier, T)
435                 ~" has method toHash, however it cannot be called with "
436                 ~typeof(val).stringof~" this.");
437             static if (__traits(compiles, __traits(getLocation, T.toHash)))
438             {
439                 enum file = __traits(getLocation, T.toHash)[0];
440                 enum line = __traits(getLocation, T.toHash)[1].stringof;
441                 pragma(msg, "  ",__traits(identifier, T),".toHash defined here: ",file,"(",line,")");
442             }
443         }
444 
445         static if (T.tupleof.length == 0)
446         {
447             return seed;
448         }
449         else static if ((is(T == struct) && !canBitwiseHash!T) || T.tupleof.length == 1)
450         {
451             static if (isChained) size_t h = seed;
452             static foreach (i, F; typeof(val.tupleof))
453             {
454                 static if (__traits(isStaticArray, F))
455                 {
456                     static if (i == 0 && !isChained) size_t h = 0;
457                     static if (F.sizeof > 0 && canBitwiseHash!F)
458                         // May use smallBytesHash instead of bytesHash.
459                         h = bytesHashWithExactSizeAndAlignment!F(toUbyte(val.tupleof[i]), h);
460                     else
461                         // We can avoid the "double hashing" the top-level version uses
462                         // for consistency with TypeInfo.getHash.
463                         foreach (ref e; val.tupleof[i])
464                             h = hashOf(e, h);
465                 }
466                 else static if (is(F == struct) || is(F == union))
467                 {
468                     static if (hasCallableToHash!F)
469                     {
470                         static if (!__traits(isSame, F, __traits(parent, val.tupleof[i].toHash))
471                             && is(typeof(val.tupleof[i] is null)))
472                         {
473                             static if (i == 0 && !isChained)
474                                 size_t h = hashOf(__traits(getMember, val.tupleof[i], __traits(getAliasThis, F)));
475                             else
476                                 h = hashOf(__traits(getMember, val.tupleof[i], __traits(getAliasThis, F)), h);
477                         }
478                         else
479                         {
480                             static if (i == 0 && !isChained)
481                                 size_t h = val.tupleof[i].toHash();
482                             else
483                                 h = hashOf(cast(size_t) val.tupleof[i].toHash(), h);
484                         }
485                     }
486                     else static if (F.tupleof.length == 1)
487                     {
488                         // Handle the single member case separately to avoid unnecessarily using bytesHash.
489                         static if (i == 0 && !isChained)
490                             size_t h = hashOf(val.tupleof[i].tupleof[0]);
491                         else
492                             h = hashOf(val.tupleof[i].tupleof[0], h);
493                     }
494                     else static if (canBitwiseHash!F)
495                     {
496                         // May use smallBytesHash instead of bytesHash.
497                         static if (i == 0 && !isChained) size_t h = 0;
498                         h = bytesHashWithExactSizeAndAlignment!F(toUbyte(val.tupleof[i]), h);
499                     }
500                     else
501                     {
502                         // Nothing special happening.
503                         static if (i == 0 && !isChained)
504                             size_t h = hashOf(val.tupleof[i]);
505                         else
506                             h = hashOf(val.tupleof[i], h);
507                     }
508                 }
509                 else
510                 {
511                     // Nothing special happening.
512                     static if (i == 0 && !isChained)
513                         size_t h = hashOf(val.tupleof[i]);
514                     else
515                         h = hashOf(val.tupleof[i], h);
516                 }
517             }
518             return h;
519         }
520         else static if (is(typeof(toUbyte(val)) == const(ubyte)[]))//CTFE ready for structs without reference fields
521         {
522             // Not using bytesHashWithExactSizeAndAlignment here because
523             // the result may differ from typeid(T).hashOf(&val).
524             return bytesHashAlignedBy!T(toUbyte(val), seed);
525         }
526         else // CTFE unsupported
527         {
528             assert(!__ctfe, "unable to compute hash of "~T.stringof~" at compile time");
529             const(ubyte)[] bytes = (() @trusted => (cast(const(ubyte)*)&val)[0 .. T.sizeof])();
530             // Not using bytesHashWithExactSizeAndAlignment here because
531             // the result may differ from typeid(T).hashOf(&val).
532             return bytesHashAlignedBy!T(bytes, seed);
533         }
534     }
535 };
536 
537 //struct or union hash
538 size_t hashOf(T)(scope const auto ref T val, size_t seed = 0)
539 if (!is(T == enum) && (is(T == struct) || is(T == union))
540     && !is(T == const) && !is(T == immutable)
541     && canBitwiseHash!T)
542 {
543     mixin(_hashOfStruct);
544 }
545 
546 //struct or union hash
547 size_t hashOf(T)(auto ref T val)
548 if (!is(T == enum) && (is(T == struct) || is(T == union))
549     && !canBitwiseHash!T)
550 {
551     mixin(_hashOfStruct);
552 }
553 
554 //struct or union hash
555 size_t hashOf(T)(auto ref T val, size_t seed)
556 if (!is(T == enum) && (is(T == struct) || is(T == union))
557     && !canBitwiseHash!T)
558 {
559     mixin(_hashOfStruct);
560 }
561 
562 //struct or union hash - https://issues.dlang.org/show_bug.cgi?id=19332 (support might be removed in future)
563 size_t hashOf(T)(scope auto ref T val, size_t seed = 0)
564 if (!is(T == enum) && (is(T == struct) || is(T == union))
565     && (is(T == const) || is(T == immutable))
566     && canBitwiseHash!T && !canBitwiseHash!(Unconst!T))
567 {
568     mixin(_hashOfStruct);
569 }
570 
571 //delegate hash. CTFE only if null.
572 @trusted @nogc nothrow pure
573 size_t hashOf(T)(scope const T val, size_t seed = 0) if (!is(T == enum) && is(T == delegate))
574 {
575     if (__ctfe)
576     {
577         if (val is null) return hashOf(size_t(0), hashOf(size_t(0), seed));
578         assert(0, "unable to compute hash of "~T.stringof~" at compile time");
579     }
580     return hashOf(val.ptr, hashOf(cast(void*) val.funcptr, seed));
581 }
582 
583 //address-based class hash. CTFE only if null.
584 @nogc nothrow pure @trusted
585 size_t hashOf(T)(scope const T val)
586 if (!is(T == enum) && (is(T == interface) || is(T == class))
587     && canBitwiseHash!T)
588 {
589     if (__ctfe) if (val is null) return 0;
590     return hashOf(cast(const void*) val);
591 }
592 
593 //address-based class hash. CTFE only if null.
594 @nogc nothrow pure @trusted
595 size_t hashOf(T)(scope const T val, size_t seed)
596 if (!is(T == enum) && (is(T == interface) || is(T == class))
597     && canBitwiseHash!T)
598 {
599     if (__ctfe) if (val is null) return hashOf(size_t(0), seed);
600     return hashOf(cast(const void*) val, seed);
601 }
602 
603 //class or interface hash. CTFE depends on toHash
604 size_t hashOf(T)(T val)
605 if (!is(T == enum) && (is(T == interface) || is(T == class))
606     && !canBitwiseHash!T)
607 {
608     static if (__traits(compiles, {size_t h = val.toHash();}))
609     {
610         static if (is(__traits(parent, val.toHash) P) && !is(immutable T* : immutable P*)
611                 && is(typeof((ref P p) => p is null)))
612             return val ? hashOf(__traits(getMember, val, __traits(getAliasThis, T))) : 0;
613         else
614             return val ? val.toHash() : 0;
615     }
616     else
617         return val ? (cast(Object)val).toHash() : 0;
618 }
619 
620 //class or interface hash. CTFE depends on toHash
621 size_t hashOf(T)(T val, size_t seed)
622 if (!is(T == enum) && (is(T == interface) || is(T == class))
623     && !canBitwiseHash!T)
624 {
625     static if (__traits(compiles, {size_t h = val.toHash();}))
626     {
627         static if (is(__traits(parent, val.toHash) P) && !is(immutable T* : immutable P*)
628                 && is(typeof((ref P p) => p is null)))
629             return hashOf(val ? hashOf(__traits(getMember, val, __traits(getAliasThis, T)))
630                               : size_t(0), seed);
631         else
632             return hashOf(val ? cast(size_t) val.toHash() : size_t(0), seed);
633     }
634     else
635         return hashOf(val ? (cast(Object)val).toHash() : 0, seed);
636 }
637 
638 //associative array hash. CTFE depends on base types
639 size_t hashOf(T)(T aa) if (!is(T == enum) && __traits(isAssociativeArray, T))
640 {
641     static if (is(typeof(aa) : V[K], K, V)) {} // Put K & V in scope.
642     static if (__traits(compiles, (ref K k, ref V v) nothrow => .hashOf(k) + .hashOf(v)))
643         scope (failure) assert(0); // Allow compiler to infer nothrow.
644 
645     if (!aa.length) return 0;
646     size_t h = 0;
647 
648     // The computed hash is independent of the foreach traversal order.
649     foreach (ref key, ref val; aa)
650         h += hashOf(hashOf(val), hashOf(key));
651     return h;
652 }
653 
654 //associative array hash. CTFE depends on base types
655 size_t hashOf(T)(T aa, size_t seed) if (!is(T == enum) && __traits(isAssociativeArray, T))
656 {
657     return hashOf(hashOf(aa), seed);
658 }
659 
660 // MurmurHash3 was written by Austin Appleby, and is placed in the public
661 // domain. The author hereby disclaims copyright to this source code.
662 
663 // This overload is for backwards compatibility.
664 @system pure nothrow @nogc
665 size_t bytesHash()(scope const(void)* buf, size_t len, size_t seed)
666 {
667     return bytesHashAlignedBy!ubyte((cast(const(ubyte)*) buf)[0 .. len], seed);
668 }
669 
670 private template bytesHashAlignedBy(AlignType)
671 {
672     alias bytesHashAlignedBy = bytesHash!(AlignType.alignof >= uint.alignof);
673 }
674 
675 private template bytesHashWithExactSizeAndAlignment(SizeAndAlignType)
676 {
677     static if (SizeAndAlignType.alignof < uint.alignof
678             ? SizeAndAlignType.sizeof <= 12
679             : SizeAndAlignType.sizeof <= 10)
680         alias bytesHashWithExactSizeAndAlignment = smallBytesHash;
681     else
682         alias bytesHashWithExactSizeAndAlignment = bytesHashAlignedBy!SizeAndAlignType;
683 }
684 
685 // Fowler/Noll/Vo hash. http://www.isthe.com/chongo/tech/comp/fnv/
686 private size_t fnv()(scope const(ubyte)[] bytes, size_t seed) @nogc nothrow pure @safe
687 {
688     static if (size_t.max <= uint.max)
689         enum prime = (1U << 24) + (1U << 8) + 0x93U;
690     else static if (size_t.max <= ulong.max)
691         enum prime = (1UL << 40) + (1UL << 8) + 0xb3UL;
692     else
693         enum prime = (size_t(1) << 88) + (size_t(1) << 8) + size_t(0x3b);
694     foreach (b; bytes)
695         seed = (seed ^ b) * prime;
696     return seed;
697 }
698 private alias smallBytesHash = fnv;
699 
700 //-----------------------------------------------------------------------------
701 // Block read - if your platform needs to do endian-swapping or can only
702 // handle aligned reads, do the conversion here
703 private uint get32bits()(scope const(ubyte)* x) @nogc nothrow pure @system
704 {
705     version (BigEndian)
706     {
707         return ((cast(uint) x[0]) << 24) | ((cast(uint) x[1]) << 16) | ((cast(uint) x[2]) << 8) | (cast(uint) x[3]);
708     }
709     else
710     {
711         return ((cast(uint) x[3]) << 24) | ((cast(uint) x[2]) << 16) | ((cast(uint) x[1]) << 8) | (cast(uint) x[0]);
712     }
713 }
714 
715 /+
716 Params:
717     dataKnownToBeAligned = whether the data is known at compile time to be uint-aligned.
718 +/
719 @nogc nothrow pure @trusted
720 private size_t bytesHash(bool dataKnownToBeAligned)(scope const(ubyte)[] bytes, size_t seed)
721 {
722     auto len = bytes.length;
723     auto data = bytes.ptr;
724     auto nblocks = len / 4;
725 
726     uint h1 = cast(uint)seed;
727 
728     enum uint c1 = 0xcc9e2d51;
729     enum uint c2 = 0x1b873593;
730     enum uint c3 = 0xe6546b64;
731 
732     //----------
733     // body
734     auto end_data = data+nblocks*uint.sizeof;
735     for (; data!=end_data; data += uint.sizeof)
736     {
737         static if (dataKnownToBeAligned)
738             uint k1 = __ctfe ? get32bits(data) : *(cast(const uint*) data);
739         else
740             uint k1 = get32bits(data);
741         k1 *= c1;
742         k1 = (k1 << 15) | (k1 >> (32 - 15));
743         k1 *= c2;
744 
745         h1 ^= k1;
746         h1 = (h1 << 13) | (h1 >> (32 - 13));
747         h1 = h1*5+c3;
748     }
749 
750     //----------
751     // tail
752     uint k1 = 0;
753 
754     switch (len & 3)
755     {
756         case 3: k1 ^= data[2] << 16; goto case;
757         case 2: k1 ^= data[1] << 8;  goto case;
758         case 1: k1 ^= data[0];
759                 k1 *= c1; k1 = (k1 << 15) | (k1 >> (32 - 15)); k1 *= c2; h1 ^= k1;
760                 goto default;
761         default:
762     }
763 
764     //----------
765     // finalization
766     h1 ^= len;
767     // Force all bits of the hash block to avalanche.
768     h1 = (h1 ^ (h1 >> 16)) * 0x85ebca6b;
769     h1 = (h1 ^ (h1 >> 13)) * 0xc2b2ae35;
770     h1 ^= h1 >> 16;
771     return h1;
772 }
773 
774 //  Check that bytesHash works with CTFE
775 pure nothrow @system @nogc unittest
776 {
777     size_t ctfeHash(string x)
778     {
779         return bytesHash(x.ptr, x.length, 0);
780     }
781 
782     enum test_str = "Sample string";
783     enum size_t hashVal = ctfeHash(test_str);
784     assert(hashVal == bytesHash(&test_str[0], test_str.length, 0));
785 
786     // Detect unintended changes to bytesHash on unaligned and aligned inputs.
787     version (BigEndian)
788     {
789         const ubyte[7] a = [99, 4, 3, 2, 1, 5, 88];
790         const uint[2] b = [0x04_03_02_01, 0x05_ff_ff_ff];
791     }
792     else
793     {
794         const ubyte[7] a = [99, 1, 2, 3, 4, 5, 88];
795         const uint[2] b = [0x04_03_02_01, 0xff_ff_ff_05];
796     }
797     // It is okay to change the below values if you make a change
798     // that you expect to change the result of bytesHash.
799     assert(bytesHash(&a[1], a.length - 2, 0) == 2727459272);
800     assert(bytesHash(&b, 5, 0) == 2727459272);
801     assert(bytesHashAlignedBy!uint((cast(const ubyte*) &b)[0 .. 5], 0) == 2727459272);
802 }