1 module cachetools.hash; 2 3 import std.traits; 4 5 /// 6 /// For classes (and structs with toHash method) we use v.toHash() to compute hash. 7 /// =============================================================================== 8 /// toHash method CAN BE @nogc or not. HashMap 'nogc' properties is inherited from this method. 9 /// toHash method MUST BE @safe or @trusted, as all HashMap code alredy safe. 10 /// 11 /// See also: https://dlang.org/spec/hash-map.html#using_classes_as_key 12 /// and https://dlang.org/spec/hash-map.html#using_struct_as_key 13 /// 14 bool UseToHashMethod(T)() { 15 return (is(T == class) || (is(T == struct) && __traits(compiles, { 16 T v = T.init; 17 hash_t h = v.toHash(); 18 }))); 19 } 20 21 hash_t hash_function(T)(in T v) @safe /* @nogc inherited from toHash method */ 22 if (UseToHashMethod!T) { 23 return v.toHash(); 24 } 25 26 hash_t hash_function(T)(in T v) @nogc @trusted if (!UseToHashMethod!T) { 27 static if (isNumeric!T) { 28 enum m = 0x5bd1e995; 29 hash_t h = v; 30 h ^= h >> 13; 31 h *= m; 32 h ^= h >> 15; 33 return h; 34 } else static if (is(T == string)) { 35 // FNV-1a hash 36 ulong h = 0xcbf29ce484222325; 37 foreach (const ubyte c; cast(ubyte[]) v) { 38 h ^= c; 39 h *= 0x100000001b3; 40 } 41 return cast(hash_t) h; 42 } else { 43 const(ubyte)[] bytes = (cast(const(ubyte)*)&v)[0 .. T.sizeof]; 44 ulong h = 0xcbf29ce484222325; 45 foreach (const ubyte c; bytes) { 46 h ^= c; 47 h *= 0x100000001b3; 48 } 49 return cast(hash_t) h; 50 } 51 } 52 53 @safe unittest { 54 assert(hash_function("abc") == cast(hash_t) 0xe71fa2190541574b); 55 56 struct A0 { 57 } 58 59 assert(!UseToHashMethod!A0); 60 61 struct A1 { 62 hash_t toHash() const @safe { 63 return 0; 64 } 65 } 66 67 assert(UseToHashMethod!A1); 68 69 // class with toHash override - will use toHash 70 class C0 { 71 override hash_t toHash() const @safe { 72 return 0; 73 } 74 } 75 76 assert(UseToHashMethod!C0); 77 C0 c0 = new C0(); 78 assert(c0.toHash() == 0); 79 80 // class without toHash override - use Object.toHash method 81 class C1 { 82 } 83 84 assert(UseToHashMethod!C1); 85 }