1 module nxt.knuthhash64;
2 
3 @safe pure nothrow @nogc:
4 
5 /** Knuth hash.
6  *
7  * See_Also: https://stackoverflow.com/a/9545731/683710
8  */
9 struct KnuthHash64()            // dummy templatized to prevent instantiation
10 {
11     @safe pure nothrow @nogc:
12 
13     pragma(msg, "WARNING: this hash really sucks collisionwise and should not be used in production!");
14 
15     /** (Re)initialize.
16      */
17     void start()
18     {
19         _result = _seedValue;
20     }
21 
22     /** Use this to feed the hash with `data`.
23      *
24      * Also implements the $(XREF range, OutputRange) interface for $(D ubyte)
25      * and $(D const(ubyte)[]).
26      */
27     void put(scope const(ubyte)[] data...) @trusted
28     {
29         foreach (elt; data)
30         {
31             _result += elt;
32             _result *= _mulFactor;
33         }
34     }
35 
36     /** Returns: the finished hash.
37      *
38      * This also calls $(LREF start) to reset the internal _state.
39      */
40     ubyte[8] finish() @trusted
41     {
42         version(D_Coverage) {} else pragma(inline, true);
43         typeof(return) bytes = (cast(ubyte*)&_result)[0 .. typeof(return).sizeof];
44         start();
45         return bytes;
46     }
47 
48     ulong get() => _result;
49 
50 private:
51     private enum _seedValue = 3074457345618258791UL;
52     private enum _mulFactor = 3074457345618258799UL;
53     ulong _result = _seedValue;
54 }
55 
56 /** Compute knuthHash-64 of input `data`, with optional seed `seed`.
57  */
58 ulong knuthhash64Of()(scope const(ubyte)[] data, ulong seed = 0)
59 {
60     auto hash = KnuthHash64!()(seed);
61     hash.start();
62     hash.put(data);
63     return hash.get();
64 }
65 
66 /** Compute knuthHash-64 of input string `data`, with optional seed `seed`.
67  */
68 ulong knuthhash64Of()(in char[] data, ulong seed = 0)
69 	=> knuthhash64Of(cast(ubyte[])data, seed);
70 
71 /// test simple `knuthhash64Of`
72 // unittest
73 // {
74 //     assert(knuthhash64Of("") == KnuthHash64!()._seedValue);
75 //     assert(knuthhash64Of("a") != KnuthHash64!()._seedValue);
76 //     assert(knuthhash64Of("a") != knuthhash64Of("b"));
77 // }
78 
79 // version(unittest)
80 // {
81 //     import std.digest : isDigest;
82 //     static assert(isDigest!(KnuthHash64!()));
83 // }