2 * implementation of fasthash
3 * http://code.google.com/p/fast-hash/
5 * Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use, copy,
11 * modify, merge, publish, distribute, sublicense, and/or sell copies
12 * of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 module iv
.hash
.fasthash
/*is aliced*/;
32 * 64-bit implementation of fasthash
38 public struct FastHash
{
44 enum M
= 0x880355f21e6d1965UL
;
47 ulong seed
; // initial seed value; MUST BE FIRST
48 ulong hash
; // current value
49 ulong accum
; // we operate 64-bit chunks; high 3 bits of accum used as counter
53 nothrow @trusted @nogc:
54 /// construct state with seed
55 this (ulong aseed
) pure { pragma(inline
, true); hash
= seed
= aseed
; }
58 void reset () pure { pragma(inline
, true); accum
= totallen
= 0; hash
= seed
; }
61 void reset (ulong aseed
) pure { pragma(inline
, true); accum
= totallen
= 0; hash
= seed
= aseed
; }
63 /// process data block
64 void put(T
) (scope const(T
)[] data
...) if (T
.sizeof
== 1) {
65 if (data
.length
== 0) return; // nothing to do
66 if (totallen
== 0) hash
= seed
;
67 auto bytes
= cast(const(ubyte)*)data
.ptr
;
68 auto len
= data
.length
;
69 if (totallen
+len
< totallen
) assert(0, "FastHash: too much data"); // overflow
73 // do we have something in accum?
75 // consume any carry bytes
76 ubyte i
= (acc
>>61)&7;
79 while (i
< 8 && len
) {
80 acc |
= (cast(ulong)(*bytes
++))<<(i
*8);
85 // got 8 bytes, process 'em
87 acc
*= 0x2127599bf4325c37UL
;
96 acc |
= (cast(ulong)i
)<<61;
99 // now process 8-byte blocks
100 assert(len
== 0 || acc
== 0);
102 foreach (immutable _
; 0..len
/8) {
104 t
= cast(ulong)bytes
[0]|
105 (cast(ulong)bytes
[1]<<8)|
106 (cast(ulong)bytes
[2]<<16)|
107 (cast(ulong)bytes
[3]<<24)|
108 (cast(ulong)bytes
[4]<<32)|
109 (cast(ulong)bytes
[5]<<40)|
110 (cast(ulong)bytes
[6]<<48)|
111 (cast(ulong)bytes
[7]<<56);
113 version(LittleEndian
) {
114 t
= *cast(const(ulong)*)bytes
;
116 t
= cast(ulong)bytes
[0]|
117 (cast(ulong)bytes
[1]<<8)|
118 (cast(ulong)bytes
[2]<<16)|
119 (cast(ulong)bytes
[3]<<24)|
120 (cast(ulong)bytes
[4]<<32)|
121 (cast(ulong)bytes
[5]<<40)|
122 (cast(ulong)bytes
[6]<<48)|
123 (cast(ulong)bytes
[7]<<56);
128 t
*= 0x2127599bf4325c37UL
;
133 // do we have something to push into accum?
134 if ((len
&= 7) != 0) {
135 foreach (immutable shift
; 0..len
) {
136 acc |
= (cast(ulong)(*bytes
++))<<(shift
*8);
138 acc |
= (cast(ulong)len
)<<61;
144 /// finalize a hash (i.e. return current result).
145 /// note that you can continue putting data, as this is not destructive
146 @property ulong result64 () const pure {
148 if (totallen
== 0) h
= seed
;
157 acc
*= 0x2127599bf4325c37UL
;
163 h
*= 0x2127599bf4325c37UL
;
168 /// finalize a hash (i.e. return current result).
169 /// note that you can continue putting data, as this is not destructive
170 @property uint result32 () const pure {
171 pragma(inline
, true);
173 // the following trick converts the 64-bit hashcode to Fermat
174 // residue, which shall retain information from both the higher
175 // and lower parts of hashcode.
176 return cast(uint)(h
-(h
>>32));
179 ulong finish64 () pure { auto res
= result64
; reset(); return res
; } /// resets state
180 ulong finish32 () pure { auto res
= result32
; reset(); return res
; } /// resets state
185 * 64-bit implementation of fasthash
191 ulong fastHash64(T
) (const(T
)[] buf
, ulong seed
=0) nothrow @trusted @nogc if (T
.sizeof
== 1) {
192 auto hh
= FastHash(seed
);
198 * 32-bit implementation of fasthash
204 uint fastHash32(T
) (const(T
)[] buf
, ulong seed
=0) nothrow @trusted @nogc if (T
.sizeof
== 1) {
205 auto hh
= FastHash(seed
);
212 * 64-bit implementation of fasthash
218 ulong fastHash64(T
) (const(T
)[] buf
, ulong seed
=0) nothrow @trusted @nogc if (T
.sizeof
> 1) {
219 auto hh
= FastHash(seed
);
220 hh
.put((cast(const(ubyte)*)buf
.ptr
)[0..buf
.length
*T
.sizeof
]);
225 * 32-bit implementation of fasthash
231 uint fastHash32(T
) (const(T
)[] buf
, ulong seed
=0) nothrow @trusted @nogc if (T
.sizeof
> 1) {
232 auto hh
= FastHash(seed
);
233 hh
.put((cast(const(ubyte)*)buf
.ptr
)[0..buf
.length
*T
.sizeof
]);
238 version(iv_hash_unittest
) unittest {
239 static assert(fastHash32("Alice & Miriel") == 0x4773e2a3U
);
240 static assert(fastHash64("Alice & Miriel") == 0xfa02b41e417696c1UL
);
244 writefln("0x%08xU", fastHash32("Alice & Miriel"));
245 writefln("0x%016xUL", fastHash64("Alice & Miriel"));
248 mixin(import("test.d"));
249 doTest
!(32, "FastHash")("Alice & Miriel", 0x4773e2a3U
);
250 doTest
!(64, "FastHash")("Alice & Miriel", 0xfa02b41e417696c1UL
);