Skip to content

Commit 9c1cd69

Browse files
committed
optimized SipHash implementation
work started from @gereeter's PR: rust-lang#13114 but adjusted bits
1 parent 246ebd2 commit 9c1cd69

File tree

1 file changed

+143
-42
lines changed

1 file changed

+143
-42
lines changed

src/libstd/hash/sip.rs

+143-42
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@
2727
use clone::Clone;
2828
use container::Container;
2929
use default::Default;
30+
use int;
3031
use io::{IoResult, Writer};
3132
use iter::Iterator;
3233
use result::Ok;
3334
use slice::ImmutableVector;
35+
use uint;
3436

3537
use super::{Hash, Hasher};
3638

@@ -43,7 +45,7 @@ pub struct SipState {
4345
v1: u64,
4446
v2: u64,
4547
v3: u64,
46-
tail: [u8, ..8], // unprocessed bytes
48+
tail: u64, // unprocessed bytes le
4749
ntail: uint, // how many bytes in tail are valid
4850
}
4951

@@ -60,7 +62,17 @@ macro_rules! u8to64_le (
6062
$buf[4+$i] as u64 << 32 |
6163
$buf[5+$i] as u64 << 40 |
6264
$buf[6+$i] as u64 << 48 |
63-
$buf[7+$i] as u64 << 56)
65+
$buf[7+$i] as u64 << 56);
66+
($buf:expr, $i:expr, $len:expr) =>
67+
({
68+
let mut t = 0;
69+
let mut out = 0u64;
70+
while t < $len {
71+
out |= $buf[t+$i] as u64 << t*8;
72+
t += 1;
73+
}
74+
out
75+
});
6476
)
6577

6678
macro_rules! rotl (
@@ -98,7 +110,7 @@ impl SipState {
98110
v1: 0,
99111
v2: 0,
100112
v3: 0,
101-
tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ],
113+
tail: 0,
102114
ntail: 0,
103115
};
104116
state.reset();
@@ -124,15 +136,7 @@ impl SipState {
124136
let mut v2 = self.v2;
125137
let mut v3 = self.v3;
126138

127-
let mut b : u64 = (self.length as u64 & 0xff) << 56;
128-
129-
if self.ntail > 0 { b |= self.tail[0] as u64 << 0; }
130-
if self.ntail > 1 { b |= self.tail[1] as u64 << 8; }
131-
if self.ntail > 2 { b |= self.tail[2] as u64 << 16; }
132-
if self.ntail > 3 { b |= self.tail[3] as u64 << 24; }
133-
if self.ntail > 4 { b |= self.tail[4] as u64 << 32; }
134-
if self.ntail > 5 { b |= self.tail[5] as u64 << 40; }
135-
if self.ntail > 6 { b |= self.tail[6] as u64 << 48; }
139+
let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
136140

137141
v3 ^= b;
138142
compress!(v0, v1, v2, v3);
@@ -147,8 +151,38 @@ impl SipState {
147151

148152
v0 ^ v1 ^ v2 ^ v3
149153
}
154+
155+
#[inline]
156+
fn write_le(&mut self, n: u64, size: uint) {
157+
self.tail |= n << 8*self.ntail;
158+
self.ntail += size;
159+
160+
if self.ntail >= 8 {
161+
let m = self.tail;
162+
163+
self.v3 ^= m;
164+
compress!(self.v0, self.v1, self.v2, self.v3);
165+
compress!(self.v0, self.v1, self.v2, self.v3);
166+
self.v0 ^= m;
167+
168+
self.ntail -= 8;
169+
if self.ntail == 0 {
170+
self.tail = 0;
171+
} else {
172+
self.tail = n >> 64 - 8*self.ntail;
173+
}
174+
}
175+
}
150176
}
151177

178+
macro_rules! make_write_le(
179+
($this:expr, $n:expr, $size:expr) => ({
180+
$this.write_le($n as u64, $size);
181+
$this.length += $size;
182+
Ok(())
183+
})
184+
)
185+
152186
impl Writer for SipState {
153187
#[inline]
154188
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
@@ -159,24 +193,13 @@ impl Writer for SipState {
159193

160194
if self.ntail != 0 {
161195
needed = 8 - self.ntail;
162-
163196
if length < needed {
164-
let mut t = 0;
165-
while t < length {
166-
self.tail[self.ntail+t] = msg[t];
167-
t += 1;
168-
}
197+
self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
169198
self.ntail += length;
170199
return Ok(());
171200
}
172201

173-
let mut t = 0;
174-
while t < needed {
175-
self.tail[self.ntail+t] = msg[t];
176-
t += 1;
177-
}
178-
179-
let m = u8to64_le!(self.tail, 0);
202+
let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;
180203

181204
self.v3 ^= m;
182205
compress!(self.v0, self.v1, self.v2, self.v3);
@@ -203,15 +226,62 @@ impl Writer for SipState {
203226
i += 8;
204227
}
205228

206-
let mut t = 0u;
207-
while t < left {
208-
self.tail[t] = msg[i+t];
209-
t += 1
210-
}
229+
self.tail = u8to64_le!(msg, i, left);
211230
self.ntail = left;
212231

213232
Ok(())
214233
}
234+
235+
#[inline]
236+
fn write_u8(&mut self, n: u8) -> IoResult<()> {
237+
make_write_le!(self, n, 1)
238+
}
239+
240+
#[inline]
241+
fn write_le_u16(&mut self, n: u16) -> IoResult<()> {
242+
make_write_le!(self, n, 2)
243+
}
244+
245+
#[inline]
246+
fn write_le_u32(&mut self, n: u32) -> IoResult<()> {
247+
make_write_le!(self, n, 4)
248+
}
249+
250+
#[inline]
251+
fn write_le_u64(&mut self, n: u64) -> IoResult<()> {
252+
make_write_le!(self, n, 8)
253+
}
254+
255+
#[inline]
256+
fn write_le_uint(&mut self, n: uint) -> IoResult<()> {
257+
make_write_le!(self, n, uint::BYTES)
258+
}
259+
260+
#[inline]
261+
fn write_i8(&mut self, n: i8) -> IoResult<()> {
262+
make_write_le!(self, n, 1)
263+
}
264+
265+
#[inline]
266+
fn write_le_i16(&mut self, n: i16) -> IoResult<()> {
267+
make_write_le!(self, n, 2)
268+
}
269+
270+
#[inline]
271+
fn write_le_i32(&mut self, n: i32) -> IoResult<()> {
272+
make_write_le!(self, n, 4)
273+
}
274+
275+
#[inline]
276+
fn write_le_i64(&mut self, n: i64) -> IoResult<()> {
277+
make_write_le!(self, n, 8)
278+
}
279+
280+
#[inline]
281+
fn write_le_int(&mut self, n: int) -> IoResult<()> {
282+
make_write_le!(self, n, int::BYTES)
283+
}
284+
215285
}
216286

217287
impl Clone for SipState {
@@ -284,6 +354,8 @@ pub fn hash_with_keys<T: Hash<SipState>>(k0: u64, k1: u64, value: &T) -> u64 {
284354
state.result()
285355
}
286356

357+
358+
287359
#[cfg(test)]
288360
mod tests {
289361
extern crate test;
@@ -517,28 +589,57 @@ mod tests {
517589
}
518590

519591
#[bench]
520-
fn bench_str(b: &mut Bencher) {
592+
fn bench_str_under_8_bytes(b: &mut Bencher) {
521593
let s = "foo";
522594
b.iter(|| {
523595
assert_eq!(hash(&s), 16262950014981195938);
524596
})
525597
}
526598

599+
#[bench]
600+
fn bench_str_of_8_bytes(b: &mut Bencher) {
601+
let s = "foobar78";
602+
b.iter(|| {
603+
assert_eq!(hash(&s), 4898293253460910787);
604+
})
605+
}
606+
607+
#[bench]
608+
fn bench_str_over_8_bytes(b: &mut Bencher) {
609+
let s = "foobarbaz0";
610+
b.iter(|| {
611+
assert_eq!(hash(&s), 10581415515220175264);
612+
})
613+
}
614+
615+
#[bench]
616+
fn bench_long_str(b: &mut Bencher) {
617+
let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
618+
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
619+
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
620+
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
621+
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
622+
officia deserunt mollit anim id est laborum.";
623+
b.iter(|| {
624+
assert_eq!(hash(&s), 17717065544121360093);
625+
})
626+
}
627+
628+
#[bench]
629+
fn bench_u64(b: &mut Bencher) {
630+
let u = 16262950014981195938u64;
631+
b.iter(|| {
632+
assert_eq!(hash(&u), 5254097107239593357);
633+
})
634+
}
635+
636+
#[deriving(Hash)]
527637
struct Compound {
528638
x: u8,
529-
y: u16,
639+
y: u64,
530640
z: ~str,
531641
}
532642

533-
impl<S: Writer> Hash<S> for Compound {
534-
#[inline]
535-
fn hash(&self, state: &mut S) {
536-
self.x.hash(state);
537-
self.y.hash(state);
538-
self.z.hash(state);
539-
}
540-
}
541-
542643
#[bench]
543644
fn bench_compound_1(b: &mut Bencher) {
544645
let compound = Compound {
@@ -547,7 +648,7 @@ mod tests {
547648
z: ~"foobarbaz",
548649
};
549650
b.iter(|| {
550-
assert_eq!(hash(&compound), 3581836382593270478);
651+
assert_eq!(hash(&compound), 15783192367317361799);
551652
})
552653
}
553654
}

0 commit comments

Comments
 (0)