1 module libd.data.hash; 2 3 import libd.util.bitwise : rol; 4 5 // Doesn't include all prime numbers in series as this is used by things like HashMap for determining size. 6 // Taken from https://github.com/skarupke/flat_hash_map/blob/master/flat_hash_map.hpp#L1124 7 // Credit to skarupe under an unknown license. 8 immutable PrimeNumberForSizeLookup = [ 9 2UL, 13UL, 17UL, 23UL, 29UL, 37UL, 47UL, 10 59UL, 73UL, 97UL, 127UL, 151UL, 197UL, 251UL, 313UL, 397UL, 11 499UL, 631UL, 797UL, 1009UL, 1259UL, 1597UL, 2011UL, 2539UL, 12 3203UL, 4027UL, 5087UL, 6421UL, 8089UL, 10193UL, 12853UL, 16193UL, 13 20399UL, 25717UL, 32401UL, 40823UL, 51437UL, 64811UL, 81649UL, 14 102877UL, 129607UL, 163307UL, 205759UL, 259229UL, 326617UL, 15 411527UL, 518509UL, 653267UL, 823117UL, 1037059UL, 1306601UL, 16 1646237UL, 2074129UL, 2613229UL, 3292489UL, 4148279UL, 5226491UL, 17 6584983UL, 8296553UL, 10453007UL, 13169977UL, 16593127UL, 20906033UL, 18 26339969UL, 33186281UL, 41812097UL, 52679969UL, 66372617UL, 19 83624237UL, 105359939UL, 132745199UL, 167248483UL, 210719881UL, 20 265490441UL, 334496971UL, 421439783UL, 530980861UL, 668993977UL, 21 842879579UL, 1061961721UL, 1337987929UL, 1685759167UL, 2123923447UL, 22 2675975881UL, 3371518343UL, 4247846927UL, 5351951779UL, 6743036717UL, 23 8495693897UL, 10703903591UL, 13486073473UL, 16991387857UL, 24 21407807219UL, 26972146961UL, 33982775741UL, 42815614441UL, 25 53944293929UL, 67965551447UL, 85631228929UL, 107888587883UL, 26 135931102921UL, 171262457903UL, 215777175787UL, 271862205833UL, 27 342524915839UL, 431554351609UL, 543724411781UL, 685049831731UL, 28 863108703229UL, 1087448823553UL, 1370099663459UL, 1726217406467UL, 29 2174897647073UL, 2740199326961UL, 3452434812973UL, 4349795294267UL, 30 5480398654009UL, 6904869625999UL, 8699590588571UL, 10960797308051UL, 31 13809739252051UL, 17399181177241UL, 21921594616111UL, 27619478504183UL, 32 34798362354533UL, 43843189232363UL, 55238957008387UL, 69596724709081UL, 33 87686378464759UL, 110477914016779UL, 139193449418173UL, 34 175372756929481UL, 220955828033581UL, 278386898836457UL, 35 350745513859007UL, 441911656067171UL, 556773797672909UL, 36 701491027718027UL, 883823312134381UL, 1113547595345903UL, 37 1402982055436147UL, 1767646624268779UL, 2227095190691797UL, 38 2805964110872297UL, 3535293248537579UL, 4454190381383713UL, 39 5611928221744609UL, 7070586497075177UL, 8908380762767489UL, 40 11223856443489329UL, 14141172994150357UL, 17816761525534927UL, 41 22447712886978529UL, 28282345988300791UL, 35633523051069991UL, 42 44895425773957261UL, 56564691976601587UL, 71267046102139967UL, 43 89790851547914507UL, 113129383953203213UL, 142534092204280003UL, 44 179581703095829107UL, 226258767906406483UL, 285068184408560057UL, 45 359163406191658253UL, 452517535812813007UL, 570136368817120201UL, 46 718326812383316683UL, 905035071625626043UL, 1140272737634240411UL, 47 1436653624766633509UL, 1810070143251252131UL, 2280545475268481167UL, 48 2873307249533267101UL, 3620140286502504283UL, 4561090950536962147UL, 49 5746614499066534157UL, 7240280573005008577UL, 9122181901073924329UL, 50 11493228998133068689UL, 14480561146010017169UL, 18446744073709551557UL 51 ]; 52 53 // Conversion of the canonical source, wrapped into an incremental struct. 54 // Original code is public domain with copyright waived. 55 @nogc nothrow 56 struct HashMurmur3_32(uint Seed) 57 { 58 static if(Seed == -1) 59 { 60 private uint _seed; 61 @safe 62 this(uint seed) pure 63 { 64 this._seed = seed; 65 } 66 } 67 else 68 private uint _seed = Seed; 69 70 @property @safe 71 uint value() pure const 72 { 73 return this._seed; 74 } 75 76 @trusted 77 void put(const void[] key) 78 { 79 const data = (cast(const(ubyte)[])key).ptr; 80 const nblocks = cast(uint)(key.length / 4); 81 82 uint h1 = this._seed; 83 84 const uint c1 = 0xcc9e2d51; 85 const uint c2 = 0x1b873593; 86 87 if(!__ctfe) 88 { 89 const blocks = cast(uint*)(data + (nblocks * 4)); 90 for(int i = -nblocks; i; i++) 91 { 92 version(LittleEndian) 93 uint k1 = blocks[i]; 94 else 95 static assert(false, "TODO for Big endian"); 96 97 k1 *= c1; 98 k1 = rol(k1, 15); 99 k1 *= c2; 100 101 h1 ^= k1; 102 h1 = rol(h1, 13); 103 h1 = h1*5+0xe6546b64; // ok 104 } 105 } 106 else // CTFE can't do reinterpret casts of different byte widths. 107 { 108 for(int i = nblocks; i; i--) 109 { 110 const blockI = (i * 4); 111 uint k1 = ( 112 (data[blockI-4] << 24) 113 | (data[blockI-3] << 16) 114 | (data[blockI-2] << 8) 115 | (data[blockI-1] << 0) 116 ); 117 118 k1 *= c1; 119 k1 = rol(k1, 15); 120 k1 *= c2; 121 122 h1 ^= k1; 123 h1 = rol(h1, 13); 124 h1 = h1*5+0xe6546b64; 125 } 126 } 127 128 const tail = (data + (nblocks * 4)); 129 130 uint k1 = 0; 131 132 final switch(key.length & 3) 133 { 134 case 3: k1 ^= tail[2] << 16; goto case; 135 case 2: k1 ^= tail[1] << 8; goto case; 136 case 1: k1 ^= tail[0]; goto case; 137 case 0: k1 *= c1; 138 k1 = rol(k1, 15); 139 k1 *= c2; 140 h1 ^= k1; 141 break; 142 } 143 144 h1 ^= key.length; 145 h1 ^= h1 >> 16; 146 h1 *= 0x85ebca6b; 147 h1 ^= h1 >> 13; 148 h1 *= 0xc2b2ae35; 149 h1 ^= h1 >> 16; 150 this._seed = h1; 151 } 152 } 153 /// 154 @("Murmur3_32") 155 unittest 156 { 157 const key = "The quick brown fox jumps over the lazy dog."; 158 const seed = 0; 159 const expected = 0xD5C48BFC; 160 161 HashMurmur3_32!seed hash; 162 hash.put(key); 163 assert(hash.value == expected); 164 } 165 166 alias Murmur3_32 = HashMurmur3_32!104_729; // Constant taken from the internet somewhere. 167 alias RtMurmur3_32 = HashMurmur3_32!(-1); 168 169 uint murmur3_32HashOf(T)(auto ref T value) 170 { 171 Murmur3_32 hasher; 172 hasher.put((&value)[0..1]); 173 return hasher.value; 174 }