Start moving core::hash to support a Hash trait. Add to_bytes::IterBytes trait.

This commit is contained in:
Graydon Hoare 2012-08-30 11:10:01 -07:00
parent ab53819a2c
commit a9619306a5
3 changed files with 413 additions and 39 deletions

View File

@ -15,6 +15,7 @@
import io::Writer;
import io::WriterUtil;
import to_bytes::IterBytes;
export Streaming, State;
export default_state;
@ -33,6 +34,21 @@
export hash_u8;
export hash_uint;
/// Types that can meaningfully be hashed should implement this.
trait Hash {
pure fn hash_keyed(k0: u64, k1: u64) -> u64;
}
// When we have default methods, won't need this.
trait HashUtil {
pure fn hash() -> u64;
}
impl <A: Hash> A: HashUtil {
#[inline(always)]
pure fn hash() -> u64 { self.hash_keyed(0,0) }
}
/// Streaming hash-functions should implement this.
trait Streaming {
fn input((&[const u8]));
@ -43,38 +59,97 @@ trait Streaming {
fn reset();
}
fn keyed(k0: u64, k1: u64, f: fn(s: &State)) -> u64 {
impl <A: IterBytes> A: Hash {
#[inline(always)]
pure fn hash_keyed(k0: u64, k1: u64) -> u64 {
unchecked {
let s = &State(k0, k1);
f(s);
for self.iter_le_bytes |bytes| {
s.input(bytes);
}
s.result_u64()
}
}
}
pure fn hash_bytes_keyed(buf: &[const u8], k0: u64, k1: u64) -> u64 {
unchecked { keyed(k0, k1, |s| s.input(buf)) }
// implementations
pure fn hash_keyed_2<A: IterBytes,
B: IterBytes>(a: &A, b: &B,
k0: u64, k1: u64) -> u64 {
unchecked {
let s = &State(k0, k1);
for a.iter_le_bytes |bytes| { s.input(bytes); }
for b.iter_le_bytes |bytes| { s.input(bytes); }
s.result_u64()
}
}
pure fn hash_str_keyed(s: &str, k0: u64, k1: u64) -> u64 {
unsafe {
do str::as_buf(s) |buf, len| {
do vec::unsafe::form_slice(buf, len) |slice| {
hash_bytes_keyed(slice, k0, k1)
pure fn hash_keyed_3<A: IterBytes,
B: IterBytes,
C: IterBytes>(a: &A, b: &B, c: &C,
k0: u64, k1: u64) -> u64 {
unchecked {
let s = &State(k0, k1);
for a.iter_le_bytes |bytes| { s.input(bytes); }
for b.iter_le_bytes |bytes| { s.input(bytes); }
for c.iter_le_bytes |bytes| { s.input(bytes); }
s.result_u64()
}
}
pure fn hash_keyed_4<A: IterBytes,
B: IterBytes,
C: IterBytes,
D: IterBytes>(a: &A, b: &B, c: &C, d: &D,
k0: u64, k1: u64) -> u64 {
unchecked {
let s = &State(k0, k1);
for a.iter_le_bytes |bytes| { s.input(bytes); }
for b.iter_le_bytes |bytes| { s.input(bytes); }
for c.iter_le_bytes |bytes| { s.input(bytes); }
for d.iter_le_bytes |bytes| { s.input(bytes); }
s.result_u64()
}
}
pure fn hash_keyed_5<A: IterBytes,
B: IterBytes,
C: IterBytes,
D: IterBytes,
E: IterBytes>(a: &A, b: &B, c: &C, d: &D, e: &E,
k0: u64, k1: u64) -> u64 {
unchecked {
let s = &State(k0, k1);
for a.iter_le_bytes |bytes| { s.input(bytes); }
for b.iter_le_bytes |bytes| { s.input(bytes); }
for c.iter_le_bytes |bytes| { s.input(bytes); }
for d.iter_le_bytes |bytes| { s.input(bytes); }
for e.iter_le_bytes |bytes| { s.input(bytes); }
s.result_u64()
}
}
pure fn hash_bytes_keyed(val: &[const u8], k0: u64, k1: u64) -> u64 {
val.hash_keyed(k0, k1)
}
pure fn hash_str_keyed(val: &str, k0: u64, k1: u64) -> u64 {
val.hash_keyed(k0, k1)
}
pure fn hash_u64_keyed(val: u64, k0: u64, k1: u64) -> u64 {
unchecked { keyed(k0, k1, |s| s.write_le_u64(val)) }
val.hash_keyed(k0, k1)
}
pure fn hash_u32_keyed(val: u32, k0: u64, k1: u64) -> u64 {
unchecked { keyed(k0, k1, |s| s.write_le_u32(val)) }
val.hash_keyed(k0, k1)
}
pure fn hash_u16_keyed(val: u16, k0: u64, k1: u64) -> u64 {
unchecked { keyed(k0, k1, |s| s.write_le_u16(val)) }
val.hash_keyed(k0, k1)
}
pure fn hash_u8_keyed(val: u8, k0: u64, k1: u64) -> u64 {
unchecked { keyed(k0, k1, |s| s.write_u8(val)) }
val.hash_keyed(k0, k1)
}
pure fn hash_uint_keyed(val: uint, k0: u64, k1: u64) -> u64 {
unchecked { keyed(k0, k1, |s| s.write_le_uint(val)) }
val.hash_keyed(k0, k1)
}
pure fn hash_bytes(val: &[const u8]) -> u64 { hash_bytes_keyed(val, 0, 0) }
@ -89,10 +164,13 @@ fn keyed(k0: u64, k1: u64, f: fn(s: &State)) -> u64 {
// Implement State as SipState
type State = SipState;
#[inline(always)]
fn State(k0: u64, k1: u64) -> State {
SipState(k0, k1)
}
#[inline(always)]
fn default_state() -> State {
State(0,0)
}
@ -109,6 +187,7 @@ struct SipState {
mut ntail: uint; // how many bytes in tail are valid
}
#[inline(always)]
fn SipState(key0: u64, key1: u64) -> SipState {
let state = SipState {
k0 : key0,
@ -129,6 +208,7 @@ fn SipState(key0: u64, key1: u64) -> SipState {
impl &SipState : io::Writer {
// Methods for io::writer
#[inline(always)]
fn write(msg: &[const u8]) {
macro_rules! u8to64_le (
@ -235,10 +315,12 @@ fn get_type() -> io::WriterType {
impl &SipState : Streaming {
#[inline(always)]
fn input(buf: &[const u8]) {
self.write(buf);
}
#[inline(always)]
fn result_u64() -> u64 {
let mut v0 = self.v0;
let mut v1 = self.v1;
@ -269,7 +351,6 @@ fn result_u64() -> u64 {
return (v0 ^ v1 ^ v2 ^ v3);
}
fn result_bytes() -> ~[u8] {
let h = self.result_u64();
~[(h >> 0) as u8,
@ -290,6 +371,7 @@ fn result_str() -> ~str {
return s;
}
#[inline(always)]
fn reset() {
self.length = 0;
self.v0 = self.k0 ^ 0x736f6d6570736575;
@ -385,7 +467,7 @@ fn to_hex_str(r: &[u8]/8) -> ~str {
while t < 64 {
debug!("siphash test %?", t);
let vec = u8to64_le!(vecs[t], 0);
let out = hash_bytes_keyed(buf, k0, k1);
let out = buf.hash_keyed(k0, k1);
debug!("got %?, expected %?", out, vec);
assert vec == out;

View File

@ -2,22 +2,314 @@
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
import io::Writer;
type Cb = fn(buf: &[const u8]) -> bool;
trait IterBytes {
fn iter_le_bytes(f: Cb);
fn iter_be_bytes(f: Cb);
}
impl u8: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
f([
self,
]);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
f([
self as u8
]);
}
}
impl u16: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
f([
self as u8,
(self >> 8) as u8
]);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
f([
(self >> 8) as u8,
self as u8
]);
}
}
impl u32: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
f([
self as u8,
(self >> 8) as u8,
(self >> 16) as u8,
(self >> 24) as u8,
]);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
f([
(self >> 24) as u8,
(self >> 16) as u8,
(self >> 8) as u8,
self as u8
]);
}
}
impl u64: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
f([
self as u8,
(self >> 8) as u8,
(self >> 16) as u8,
(self >> 24) as u8,
(self >> 32) as u8,
(self >> 40) as u8,
(self >> 48) as u8,
(self >> 56) as u8
]);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
f([
(self >> 56) as u8,
(self >> 48) as u8,
(self >> 40) as u8,
(self >> 32) as u8,
(self >> 24) as u8,
(self >> 16) as u8,
(self >> 8) as u8,
self as u8
]);
}
}
impl i8: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as u8).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as u8).iter_be_bytes(f) }
}
impl i16: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as u16).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as u16).iter_be_bytes(f) }
}
impl i32: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as u32).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as u32).iter_be_bytes(f) }
}
impl i64: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as u64).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as u64).iter_be_bytes(f) }
}
#[cfg(target_word_size = "32")]
impl uint: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as u32).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as u32).iter_be_bytes(f) }
}
#[cfg(target_word_size = "64")]
impl uint: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as u64).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as u64).iter_be_bytes(f) }
}
impl int: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { (self as uint).iter_le_bytes(f) }
#[inline(always)]
fn iter_be_bytes(f: Cb) { (self as uint).iter_be_bytes(f) }
}
impl ~[const u8]: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { f(self); }
#[inline(always)]
fn iter_be_bytes(f: Cb) { f(self); }
}
impl @[const u8]: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) { f(self); }
#[inline(always)]
fn iter_be_bytes(f: Cb) { f(self); }
}
impl<A: IterBytes> &[const A]: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
for self.each |elt| {
do elt.iter_le_bytes |bytes| {
f(bytes)
}
}
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
for self.each |elt| {
do elt.iter_be_bytes |bytes| {
f(bytes)
}
}
}
}
fn iter_le_bytes_2<A: IterBytes, B: IterBytes>(a: &A, b: &B, f: Cb) {
let mut flag = true;
a.iter_le_bytes(|bytes| {flag = f(bytes); flag});
if !flag { return; }
b.iter_le_bytes(|bytes| {flag = f(bytes); flag});
}
fn iter_be_bytes_2<A: IterBytes, B: IterBytes>(a: &A, b: &B, f: Cb) {
let mut flag = true;
a.iter_be_bytes(|bytes| {flag = f(bytes); flag});
if !flag { return; }
b.iter_be_bytes(|bytes| {flag = f(bytes); flag});
}
fn iter_le_bytes_3<A: IterBytes,
B: IterBytes,
C: IterBytes>(a: &A, b: &B, c: &C, f: Cb) {
let mut flag = true;
a.iter_le_bytes(|bytes| {flag = f(bytes); flag});
if !flag { return; }
b.iter_le_bytes(|bytes| { flag = f(bytes); flag});
if !flag { return; }
c.iter_le_bytes(|bytes| {flag = f(bytes); flag});
}
fn iter_be_bytes_3<A: IterBytes,
B: IterBytes,
C: IterBytes>(a: &A, b: &B, c: &C, f: Cb) {
let mut flag = true;
a.iter_be_bytes(|bytes| {flag = f(bytes); flag});
if !flag { return; }
b.iter_be_bytes(|bytes| {flag = f(bytes); flag});
if !flag { return; }
c.iter_be_bytes(|bytes| {flag = f(bytes); flag});
}
impl &str: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
do str::byte_slice(self) |bytes| {
f(bytes);
}
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
do str::byte_slice(self) |bytes| {
f(bytes);
}
}
}
impl ~str: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
do str::byte_slice(self) |bytes| {
f(bytes);
}
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
do str::byte_slice(self) |bytes| {
f(bytes);
}
}
}
impl @str: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
do str::byte_slice(self) |bytes| {
f(bytes);
}
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
do str::byte_slice(self) |bytes| {
f(bytes);
}
}
}
impl<A: IterBytes> &A: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
(*self).iter_le_bytes(f);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
(*self).iter_be_bytes(f);
}
}
impl<A: IterBytes> @A: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
(*self).iter_le_bytes(f);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
(*self).iter_be_bytes(f);
}
}
impl<A: IterBytes> ~A: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
(*self).iter_le_bytes(f);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
(*self).iter_be_bytes(f);
}
}
trait ToBytes {
fn to_bytes() -> ~[u8];
fn to_le_bytes() -> ~[u8];
fn to_be_bytes() -> ~[u8];
}
impl ~[u8]: ToBytes {
fn to_bytes() -> ~[u8] { copy self }
}
impl<A: IterBytes> A: ToBytes {
fn to_le_bytes() -> ~[u8] {
let buf = io::mem_buffer();
for self.iter_le_bytes |bytes| {
buf.write(bytes)
}
io::mem_buffer_buf(buf)
}
fn to_be_bytes() -> ~[u8] {
let buf = io::mem_buffer();
for self.iter_be_bytes |bytes| {
buf.write(bytes)
}
io::mem_buffer_buf(buf)
}
impl @~[u8]: ToBytes {
fn to_bytes() -> ~[u8] { copy *self }
}
impl ~str: ToBytes {
fn to_bytes() -> ~[u8] { str::to_bytes(self) }
}
impl @(~str): ToBytes {
fn to_bytes() -> ~[u8] { str::to_bytes(*self) }
}

View File

@ -1168,7 +1168,7 @@ fn reverse<T>(v: ~[mut T]) {
* Return true to continue, false to break.
*/
#[inline(always)]
pure fn each<T>(v: &[T], f: fn(T) -> bool) {
pure fn each<T>(v: &[const T], f: fn(T) -> bool) {
do vec::as_buf(v) |p, n| {
let mut n = n;
let mut p = p;
@ -1206,7 +1206,7 @@ fn reverse<T>(v: ~[mut T]) {
* Return true to continue, false to break.
*/
#[inline(always)]
pure fn eachi<T>(v: &[T], f: fn(uint, T) -> bool) {
pure fn eachi<T>(v: &[const T], f: fn(uint, T) -> bool) {
do vec::as_buf(v) |p, n| {
let mut i = 0u;
let mut p = p;
@ -1916,12 +1916,12 @@ fn memmove(dst: &[mut u8], src: &[const u8], count: uint) {
// This cannot be used with iter-trait.rs because of the region pointer
// required in the slice.
impl<A> &[A]: iter::BaseIter<A> {
impl<A> &[const A]: iter::BaseIter<A> {
pure fn each(blk: fn(A) -> bool) { each(self, blk) }
pure fn size_hint() -> Option<uint> { Some(len(self)) }
}
impl<A> &[A]: iter::ExtendedIter<A> {
impl<A> &[const A]: iter::ExtendedIter<A> {
pure fn eachi(blk: fn(uint, A) -> bool) { iter::eachi(self, blk) }
pure fn all(blk: fn(A) -> bool) -> bool { iter::all(self, blk) }
pure fn any(blk: fn(A) -> bool) -> bool { iter::any(self, blk) }