1 module yu.algorithm.hash;
2 
3 import yu.traits : isCharByte;
4 
5 @nogc:
6 
7 uint SDBMHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
8 {
9     uint hash = 0;
10     foreach(ch; str)// equivalent to: hash = 65599*hash + (*str++);
11         hash = ch + (hash << 6) + (hash << 16) - hash;
12     return (hash & 0x7FFFFFFF);
13 }
14 
15 // RS Hash Function
16 uint RSHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
17 {
18     uint b = 378551;
19     uint a = 63689;
20     uint hash = 0;
21     
22     foreach(ch; str)
23     {
24         hash = hash * a + ch;
25         a *= b;
26     }
27     
28     return (hash & 0x7FFFFFFF);
29 }
30 
31 // JS Hash Function
32 uint JSHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
33 {
34     uint hash = 1315423911;
35     
36     foreach(ch; str)
37         hash ^= ((hash << 5) + ch + (hash >> 2));
38     
39     return (hash & 0x7FFFFFFF);
40 }
41 
42 // P. J. Weinberger Hash Function
43 uint PJWHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
44 {
45     enum BitsInUnignedInt  = cast(uint)(uint.sizeof * 8);
46     enum ThreeQuarters    = cast(uint)((BitsInUnignedInt  * 3) / 4);
47     enum OneEighth        = cast(uint)(BitsInUnignedInt / 8);
48     enum HighBits         = cast(uint)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
49     uint hash             = 0;
50     uint test             = 0;
51     
52     foreach(ch; str)
53     {
54         hash = (hash << OneEighth) + ch;
55         if ((test = hash & HighBits) != 0)
56         {
57             hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
58         }
59     }
60     
61     return (hash & 0x7FFFFFFF);
62 }
63 
64 // ELF Hash Function
65 uint ELFHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
66 {
67     uint hash = 0;
68     uint x    = 0;
69     
70     foreach(ch; str)
71     {
72         hash = (hash << 4) + ch;
73         if ((x = hash & 0xF0000000L) != 0)
74         {
75             hash ^= (x >> 24);
76             hash &= ~x;
77         }
78     }
79     
80     return (hash & 0x7FFFFFFF);
81 }
82 
83 // BKDR Hash Function
84 uint BKDRHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
85 {
86     enum seed = 131; // 31 131 1313 13131 131313 etc..
87     uint hash = 0;
88     
89     foreach(ch; str)
90         hash = hash * seed + ch;
91     
92     return (hash & 0x7FFFFFFF);
93 }
94 
95 // DJB Hash Function
96 uint DJBHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
97 {
98     uint hash = 5381;
99     
100     foreach(ch; str)
101         hash += (hash << 5) + ch;
102     
103     return (hash & 0x7FFFFFFF);
104 }
105 
106 // AP Hash Function
107 uint APHash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
108 {
109     uint hash = 0;
110     foreach(i,ch; str)
111     {
112         if ((i & 1) == 0)
113             hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
114         else
115             hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
116     }
117     
118     return (hash & 0x7FFFFFFF);
119 }
120  
121 //Jenkins hash function one-at-a-time
122 uint JKOhash(CHAR)(const CHAR[] str) if(isCharByte!CHAR)
123 {
124     uint hash = 0;
125     foreach(ch; str)
126     {
127         hash += ch;
128         hash += (hash << 10);
129         hash ^= (hash >> 6);
130     }
131     hash += (hash << 3);
132     hash ^= (hash >> 11);
133     hash += (hash << 15);
134     return hash;
135 }
136 
137 size_t Murmur3Hash(CHAR)(const CHAR[] str, size_t seed = 0) if(isCharByte!CHAR)
138 {
139     import core.internal.hash : bytesHash;
140     return bytesHash(str.ptr, str.length,seed);
141 }
142 
143 unittest {
144     string hash = "tets hash!!!";
145     const ubyte[] thash = cast(const ubyte[])hash;
146     assert(SDBMHash(hash) == SDBMHash(thash));
147     assert(RSHash(hash) == RSHash(thash));
148     assert(JSHash(hash) == JSHash(thash));
149     assert(PJWHash(hash) == PJWHash(thash));
150     assert(BKDRHash(hash) == BKDRHash(thash));
151     assert(DJBHash(hash) == DJBHash(thash));
152     assert(APHash(hash) == APHash(thash));
153     assert(JKOhash(hash) == JKOhash(thash));
154     assert(Murmur3Hash(hash) == Murmur3Hash(thash));
155 }