libcore: Remove mutable fields from hash

This commit is contained in:
Patrick Walton 2013-05-03 11:30:30 -07:00
parent 2961997f16
commit 4dc1c2976d
6 changed files with 160 additions and 111 deletions

View file

@ -19,12 +19,16 @@
* CPRNG like rand::rng.
*/
use io;
use io::Writer;
#[cfg(stage0)]
use cast;
use rt::io::Writer;
use to_bytes::IterBytes;
use uint;
use vec;
// Alias `SipState` to `State`.
pub use State = hash::SipState;
/**
* Types that can meaningfully be hashed should implement this.
*
@ -65,20 +69,32 @@ impl<A:Hash> HashUtil for A {
/// Streaming hash-functions should implement this.
pub trait Streaming {
fn input(&self, (&const [u8]));
fn input(&mut self, &[u8]);
// These can be refactored some when we have default methods.
fn result_bytes(&self) -> ~[u8];
fn result_str(&self) -> ~str;
fn result_u64(&self) -> u64;
fn reset(&self);
fn result_bytes(&mut self) -> ~[u8];
fn result_str(&mut self) -> ~str;
fn result_u64(&mut self) -> u64;
fn reset(&mut self);
}
// XXX: Ugly workaround for bootstrapping.
#[cfg(stage0)]
fn transmute_for_stage0<'a>(bytes: &'a [const u8]) -> &'a [u8] {
unsafe {
cast::transmute(bytes)
}
}
#[cfg(not(stage0))]
fn transmute_for_stage0<'a>(bytes: &'a [u8]) -> &'a [u8] {
bytes
}
impl<A:IterBytes> Hash for A {
#[inline(always)]
fn hash_keyed(&self, k0: u64, k1: u64) -> u64 {
let s = &State(k0, k1);
let mut s = State::new(k0, k1);
for self.iter_bytes(true) |bytes| {
s.input(bytes);
s.input(transmute_for_stage0(bytes));
}
s.result_u64()
}
@ -86,32 +102,56 @@ impl<A:IterBytes> Hash for A {
fn hash_keyed_2<A: IterBytes,
B: IterBytes>(a: &A, b: &B, k0: u64, k1: u64) -> u64 {
let s = &State(k0, k1);
for a.iter_bytes(true) |bytes| { s.input(bytes); }
for b.iter_bytes(true) |bytes| { s.input(bytes); }
let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64()
}
fn hash_keyed_3<A: IterBytes,
B: IterBytes,
C: IterBytes>(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 {
let s = &State(k0, k1);
for a.iter_bytes(true) |bytes| { s.input(bytes); }
for b.iter_bytes(true) |bytes| { s.input(bytes); }
for c.iter_bytes(true) |bytes| { s.input(bytes); }
let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for c.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64()
}
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 {
let s = &State(k0, k1);
for a.iter_bytes(true) |bytes| { s.input(bytes); }
for b.iter_bytes(true) |bytes| { s.input(bytes); }
for c.iter_bytes(true) |bytes| { s.input(bytes); }
for d.iter_bytes(true) |bytes| { s.input(bytes); }
D: IterBytes>(
a: &A,
b: &B,
c: &C,
d: &D,
k0: u64,
k1: u64)
-> u64 {
let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for c.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for d.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64()
}
@ -119,58 +159,68 @@ 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 {
let s = &State(k0, k1);
for a.iter_bytes(true) |bytes| { s.input(bytes); }
for b.iter_bytes(true) |bytes| { s.input(bytes); }
for c.iter_bytes(true) |bytes| { s.input(bytes); }
for d.iter_bytes(true) |bytes| { s.input(bytes); }
for e.iter_bytes(true) |bytes| { s.input(bytes); }
E: IterBytes>(
a: &A,
b: &B,
c: &C,
d: &D,
e: &E,
k0: u64,
k1: u64)
-> u64 {
let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for c.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for d.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for e.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64()
}
// Implement State as SipState
pub type State = SipState;
#[inline(always)]
pub fn State(k0: u64, k1: u64) -> State {
SipState(k0, k1)
}
#[inline(always)]
pub fn default_state() -> State {
State(0,0)
State::new(0, 0)
}
struct SipState {
k0: u64,
k1: u64,
mut length: uint, // how many bytes we've processed
mut v0: u64, // hash state
mut v1: u64,
mut v2: u64,
mut v3: u64,
mut tail: [u8, ..8], // unprocessed bytes
mut ntail: uint, // how many bytes in tail are valid
length: uint, // how many bytes we've processed
v0: u64, // hash state
v1: u64,
v2: u64,
v3: u64,
tail: [u8, ..8], // unprocessed bytes
ntail: uint, // how many bytes in tail are valid
}
#[inline(always)]
fn SipState(key0: u64, key1: u64) -> SipState {
let state = SipState {
k0 : key0,
k1 : key1,
mut length : 0u,
mut v0 : 0u64,
mut v1 : 0u64,
mut v2 : 0u64,
mut v3 : 0u64,
mut tail : [0u8,0,0,0,0,0,0,0],
mut ntail : 0u,
};
(&state).reset();
state
impl SipState {
#[inline(always)]
fn new(key0: u64, key1: u64) -> SipState {
let mut state = SipState {
k0: key0,
k1: key1,
length: 0,
v0: 0,
v1: 0,
v2: 0,
v3: 0,
tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ],
ntail: 0,
};
state.reset();
state
}
}
// sadly, these macro definitions can't appear later,
@ -207,12 +257,10 @@ macro_rules! compress (
)
impl io::Writer for SipState {
impl Writer for SipState {
// Methods for io::writer
#[inline(always)]
fn write(&self, msg: &const [u8]) {
fn write(&mut self, msg: &[u8]) {
let length = msg.len();
self.length += length;
@ -272,29 +320,19 @@ impl io::Writer for SipState {
self.ntail = left;
}
fn seek(&self, _x: int, _s: io::SeekStyle) {
fail!();
}
fn tell(&self) -> uint {
self.length
}
fn flush(&self) -> int {
0
}
fn get_type(&self) -> io::WriterType {
io::File
fn flush(&mut self) {
// No-op
}
}
impl Streaming for SipState {
#[inline(always)]
fn input(&self, buf: &const [u8]) {
fn input(&mut self, buf: &[u8]) {
self.write(buf);
}
#[inline(always)]
fn result_u64(&self) -> u64 {
fn result_u64(&mut self) -> u64 {
let mut v0 = self.v0;
let mut v1 = self.v1;
let mut v2 = self.v2;
@ -324,7 +362,7 @@ impl Streaming for SipState {
return (v0 ^ v1 ^ v2 ^ v3);
}
fn result_bytes(&self) -> ~[u8] {
fn result_bytes(&mut self) -> ~[u8] {
let h = self.result_u64();
~[(h >> 0) as u8,
(h >> 8) as u8,
@ -337,7 +375,7 @@ impl Streaming for SipState {
]
}
fn result_str(&self) -> ~str {
fn result_str(&mut self) -> ~str {
let r = self.result_bytes();
let mut s = ~"";
for vec::each(r) |b| {
@ -347,7 +385,7 @@ impl Streaming for SipState {
}
#[inline(always)]
fn reset(&self) {
fn reset(&mut self) {
self.length = 0;
self.v0 = self.k0 ^ 0x736f6d6570736575;
self.v1 = self.k1 ^ 0x646f72616e646f6d;
@ -529,4 +567,4 @@ mod tests {
val & !(0xff << (byte * 8))
}
}
}
}

View file

@ -22,9 +22,9 @@ use util::ppaux;
use core::hash::Streaming;
use core::hash;
use core::io::WriterUtil;
use core::libc::{c_int, c_uint};
use core::os::consts::{macos, freebsd, linux, android, win32};
use core::rt::io::Writer;
use core::run;
use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name};
@ -41,6 +41,11 @@ pub enum output_type {
output_type_exe,
}
fn write_string<W:Writer>(writer: &mut W, string: &str) {
let buffer = str::as_bytes_slice(string);
writer.write(buffer);
}
pub fn llvm_err(sess: Session, msg: ~str) -> ! {
unsafe {
let cstr = llvm::LLVMRustGetLastError();
@ -458,9 +463,11 @@ pub mod write {
*
*/
pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
symbol_hasher: &hash::State) -> LinkMeta {
pub fn build_link_meta(sess: Session,
c: &ast::crate,
output: &Path,
symbol_hasher: &mut hash::State)
-> LinkMeta {
struct ProvidedMetas {
name: Option<@str>,
vers: Option<@str>,
@ -498,7 +505,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
}
// This calculates CMH as defined above
fn crate_meta_extras_hash(symbol_hasher: &hash::State,
fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
cmh_items: ~[@ast::meta_item],
dep_hashes: ~[~str]) -> @str {
fn len_and_str(s: &str) -> ~str {
@ -511,17 +518,17 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
let cmh_items = attr::sort_meta_items(cmh_items);
fn hash(symbol_hasher: &hash::State, m: &@ast::meta_item) {
fn hash(symbol_hasher: &mut hash::State, m: &@ast::meta_item) {
match m.node {
ast::meta_name_value(key, value) => {
symbol_hasher.write_str(len_and_str(*key));
symbol_hasher.write_str(len_and_str_lit(value));
write_string(symbol_hasher, len_and_str(*key));
write_string(symbol_hasher, len_and_str_lit(value));
}
ast::meta_word(name) => {
symbol_hasher.write_str(len_and_str(*name));
write_string(symbol_hasher, len_and_str(*name));
}
ast::meta_list(name, ref mis) => {
symbol_hasher.write_str(len_and_str(*name));
write_string(symbol_hasher, len_and_str(*name));
for mis.each |m_| {
hash(symbol_hasher, m_);
}
@ -535,7 +542,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
}
for dep_hashes.each |dh| {
symbol_hasher.write_str(len_and_str(*dh));
write_string(symbol_hasher, len_and_str(*dh));
}
// tjc: allocation is unfortunate; need to change core::hash
@ -596,23 +603,26 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
}
}
pub fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str {
pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
symbol_hasher.result_str()
}
// This calculates STH for a symbol, as defined above
pub fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &hash::State, t: ty::t,
link_meta: LinkMeta) -> @str {
pub fn symbol_hash(tcx: ty::ctxt,
symbol_hasher: &mut hash::State,
t: ty::t,
link_meta: LinkMeta)
-> @str {
// NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate.
symbol_hasher.reset();
symbol_hasher.write_str(link_meta.name);
symbol_hasher.write_str(~"-");
symbol_hasher.write_str(link_meta.extras_hash);
symbol_hasher.write_str(~"-");
symbol_hasher.write_str(encoder::encoded_ty(tcx, t));
write_string(symbol_hasher, link_meta.name);
write_string(symbol_hasher, ~"-");
write_string(symbol_hasher, link_meta.extras_hash);
write_string(symbol_hasher, ~"-");
write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
let mut hash = truncated_hash_result(symbol_hasher);
// Prefix with _ so that it never blends into adjacent digits
str::unshift_char(&mut hash, '_');

View file

@ -2987,9 +2987,8 @@ pub fn trans_crate(sess: session::Session,
emap2: resolve::ExportMap2,
maps: astencode::Maps) -> (ModuleRef, LinkMeta) {
let symbol_hasher = @hash::default_state();
let link_meta =
link::build_link_meta(sess, crate, output, symbol_hasher);
let symbol_hasher = @mut hash::default_state();
let link_meta = link::build_link_meta(sess, crate, output, symbol_hasher);
let reachable = reachable::find_reachable(
&crate.node.module,
emap2,

View file

@ -207,7 +207,7 @@ pub struct CrateContext {
adt_reprs: @mut HashMap<ty::t, @adt::Repr>,
names: namegen,
next_addrspace: addrspace_gen,
symbol_hasher: @hash::State,
symbol_hasher: @mut hash::State,
type_hashcodes: @mut HashMap<ty::t, @str>,
type_short_names: @mut HashMap<ty::t, ~str>,
all_llvm_symbols: @mut HashSet<@~str>,

View file

@ -230,6 +230,7 @@ pub fn future_writer_factory(
let markdown_ch = markdown_ch.clone();
do task::spawn || {
let (writer, future) = future_writer();
let mut future = future;
writer_ch.send(writer);
let s = future.get();
markdown_ch.send((copy page, s));

View file

@ -11,6 +11,7 @@
use core::*;
use core::cmp::Ord;
use core::hash::Streaming;
use core::rt::io::Writer;
use rustc::driver::{driver, session};
use rustc::driver::session::{lib_crate, unknown_crate};
use rustc::metadata::filesearch;
@ -367,9 +368,9 @@ pub fn error(msg: ~str) {
}
pub fn hash(data: ~str) -> ~str {
let hasher = &hash::default_state();
hasher.write_str(data);
let mut hasher = hash::default_state();
let buffer = str::as_bytes_slice(data);
hasher.write(buffer);
hasher.result_str()
}