1 /** Various hash functions, including integer ones. 2 */ 3 module nxt.hash_functions; 4 5 import std.traits : isIntegral; 6 7 pragma(inline, true) 8 @safe nothrow: 9 10 /** See_Also: http://forum.dlang.org/post/o1igoc$21ma$1@digitalmars.com 11 * 12 * Doesn't work: integers are returned as is. 13 */ 14 size_t typeidHashOf(T)(in T x) @trusted 15 { 16 return typeid(T).getHash(&x); // TODO why not pure @nogc? 17 } 18 19 unittest 20 { 21 // TODO auto x = typeidHashOf(cast(int)17); 22 } 23 24 hash_t hashOfTypeInfoPtr(TypeInfo_Class typeinfo) @trusted pure nothrow @nogc 25 { 26 assert(typeof(typeinfo).alignof == 8); 27 return (cast(hash_t)(cast(void*)typeinfo) >> 3); 28 } 29 30 size_t fibonacci_hash(hash_t hash) @safe pure nothrow @nogc 31 { 32 return (hash * 11400714819323198485LU); 33 } 34 35 /** Hash that incorporates the hash of `typeid` bit-xored with `hashOf(a)`. 36 * 37 * See_Also: https://forum.dlang.org/post/lxqoknwuujbymolnlyfw@forum.dlang.org 38 */ 39 hash_t hashOfPolymorphic(Class)(Class a) @trusted pure nothrow @nogc 40 if (is(Class == class)) 41 { 42 static assert(typeid(Class).alignof == 8); 43 // const class_typeid_hash = (cast(hash_t)(cast(void*)typeid(Class)) >> 3) 44 import core.internal.hash : hashOf; 45 return fibonacci_hash(hashOf(cast(void*)typeid(a))) ^ hashOf(a); 46 } 47 48 version(unittest) 49 { 50 private static: 51 52 class Thing 53 { 54 } 55 56 class Expr : Thing 57 { 58 @safe pure nothrow @nogc: 59 alias Data = string; 60 this(Data data) 61 { 62 this.data = data; 63 } 64 @property override hash_t toHash() const @safe pure nothrow @nogc 65 { 66 return hashOf(data); 67 } 68 Data data; 69 } 70 71 class NounExpr : Expr 72 { 73 @safe pure nothrow @nogc: 74 this(Data data) 75 { 76 super(data); 77 } 78 @property override hash_t toHash() const @safe pure nothrow @nogc 79 { 80 return hashOf(data); 81 } 82 } 83 84 class Year : Thing 85 { 86 @safe pure nothrow @nogc: 87 alias Data = long; 88 @property override hash_t toHash() const @safe pure nothrow @nogc 89 { 90 return hashOf(data); 91 } 92 Data data; 93 } 94 } 95 96 @safe pure nothrow unittest 97 { 98 auto car1 = new Expr("car"); 99 auto car2 = new Expr("car"); 100 auto bar1 = new Expr("bar"); 101 auto ncar = new NounExpr("car"); 102 103 void testEqual() @safe pure nothrow @nogc 104 { 105 assert(hashOf(car1) == hashOf(car2)); 106 assert(hashOfPolymorphic(car1) == hashOfPolymorphic(car2)); 107 } 108 109 void testDifferent1() @safe pure nothrow @nogc 110 { 111 assert(hashOf(car1) != hashOf(bar1)); 112 assert(hashOfPolymorphic(car1) != hashOfPolymorphic(bar1)); 113 } 114 115 void testDifferent2() @safe pure nothrow @nogc 116 { 117 assert(hashOf(car1) == hashOf(ncar)); 118 assert(hashOfPolymorphic(car1) != hashOfPolymorphic(ncar)); 119 } 120 121 testEqual(); 122 testDifferent1(); 123 testDifferent2(); 124 } 125 126 pure @nogc: 127 128 /** Dummy-hash for benchmarking performance of HashSet. */ 129 ulong identityHash64Of(T)(in T x) 130 if (isIntegral!T && 131 T.sizeof <= ulong.sizeof) 132 { 133 return x; // maps -1 to ulong.max 134 } 135 136 unittest 137 { 138 assert(identityHash64Of(-1) == ulong.max); 139 assert(identityHash64Of(int.max) == int.max); 140 assert(identityHash64Of(ulong.max) == ulong.max); 141 } 142 143 /** Mueller integer hash function (bit mixer) A (32-bit). 144 * 145 * See_Also: https://stackoverflow.com/a/12996028/683710 146 * See_Also: http://zimbry.blogspot.se/2011/09/better-bit-mixing-improving-on.html 147 */ 148 uint muellerHash32(uint x) 149 { 150 x = ((x >> 16) ^ x) * 0x45d9f3b; 151 x = ((x >> 16) ^ x) * 0x45d9f3b; 152 x = (x >> 16) ^ x; 153 return x; 154 } 155 156 /** Mueller integer hash function (bit mixer) A (64-bit). 157 * 158 * Based on splitmix64, which seems to be based on the blog article "Better Bit 159 * Mixing" (mix 13). 160 * 161 * See_Also: https://stackoverflow.com/a/12996028/683710 162 * See_Also: http://zimbry.blogspot.se/2011/09/better-bit-mixing-improving-on.html 163 * See_Also: http://xorshift.di.unimi.it/splitmix64.c 164 */ 165 ulong muellerHash64(T)(T x) 166 if (isIntegral!T && 167 T.sizeof <= ulong.sizeof) 168 { 169 typeof(return) y = x; 170 y = (y ^ (y >> 30)) * 0xbf58476d1ce4e5b9UL; 171 y = (y ^ (y >> 27)) * 0x94d049bb133111ebUL; 172 y = y ^ (y >> 31); 173 return y; 174 } 175 176 /** Thomas Wang 64-bit mix integer hash function. 177 * 178 * See_Also: https://gist.github.com/badboy/6267743#64-bit-mix-functions 179 */ 180 public ulong wangMixHash64(ulong x) 181 { 182 x = (~x) + (x << 21); // x = (x << 21) - x - 1; 183 x = x ^ (x >>> 24); 184 x = (x + (x << 3)) + (x << 8); // x * 265 185 x = x ^ (x >>> 14); 186 x = (x + (x << 2)) + (x << 4); // x * 21 187 x = x ^ (x >>> 28); 188 x = x + (x << 31); 189 return x; 190 } 191 192 unittest 193 { 194 assert(wangMixHash64(0) == 8633297058295171728UL); 195 assert(wangMixHash64(1) == 6614235796240398542UL); 196 }